eflips-depot 4.3.17__py3-none-any.whl → 4.3.19__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,586 @@
1
+ import datetime
2
+ import itertools
3
+ import logging
4
+ from datetime import timedelta
5
+ from typing import List, Dict
6
+
7
+ from eflips.model import Event, EventType, Rotation, Vehicle, Area
8
+ from sqlalchemy import select
9
+
10
+ from eflips.depot import SimpleVehicle, ProcessStatus
11
+
12
+
13
+ def get_finished_schedules_per_vehicle(
14
+ dict_of_events, list_of_finished_trips: List, db_vehicle_id: int
15
+ ):
16
+ """
17
+ This function completes the following tasks:
18
+
19
+ 1. It gets the finished non-copy schedules of the current vehicle,
20
+ which will be used in :func:`_update_vehicle_in_rotation()`.
21
+
22
+ 2. It fills the dictionary of events with the trip_ids of the current vehicle.
23
+
24
+ 3. It returns an earliest and a latest time according to this vehicle's schedules. Only processes happening within
25
+ this time window will be handled later.
26
+
27
+ Usually the earliest time is the departure time of the last copy trip in the "early-shifted" copy schedules
28
+ and the lastest time is the departure time of the first copy trip in the "late-shifted" copy schedules.
29
+
30
+ # If the vehicle's first trip is a non-copy trip, the earliest time is the departure time of the first trip. If the
31
+ # vehicle's last trip is a non-copy trip, the latest time is the departure time of the last trip.
32
+
33
+ :param dict_of_events: An ordered dictionary storing the data related to an event. The keys are the start times of
34
+ the events.
35
+ :param list_of_finished_trips: A list of finished trips of a vehicle directly from
36
+ :class:`eflips.depot.simple_vehicle.SimpleVehicle` object.
37
+
38
+ :param db_vehicle_id: The vehicle id in the database.
39
+
40
+ :return: A tuple of three elements. The first element is a list of finished schedules of the vehicle. The second and
41
+ third elements are the earliest and latest time of the vehicle's schedules.
42
+ """
43
+ finished_schedules = []
44
+
45
+ list_of_finished_trips.sort(key=lambda x: x.atd)
46
+ earliest_time = None
47
+ latest_time = None
48
+
49
+ for i in range(len(list_of_finished_trips)):
50
+ assert list_of_finished_trips[i].atd == list_of_finished_trips[i].std, (
51
+ "The trip {current_trip.ID} is delayed. The simulation doesn't "
52
+ "support delayed trips for now."
53
+ )
54
+
55
+ if list_of_finished_trips[i].is_copy is False:
56
+ current_trip = list_of_finished_trips[i]
57
+
58
+ finished_schedules.append((int(current_trip.ID), db_vehicle_id))
59
+ dict_of_events[current_trip.atd] = {
60
+ "type": "Trip",
61
+ "id": int(current_trip.ID),
62
+ }
63
+ if i == 0:
64
+ raise ValueError(
65
+ f"New Vehicle required for the trip {current_trip.ID}, which suggests the fleet or the "
66
+ f"infrastructure might not be enough for the full electrification. Please add charging "
67
+ f"interfaces or increase charging power ."
68
+ )
69
+
70
+ elif i != 0 and i == len(list_of_finished_trips) - 1:
71
+ # Vehicle's last trip is a non-copy trip
72
+ if earliest_time is None:
73
+ earliest_time = list_of_finished_trips[i - 1].ata
74
+ latest_time = list_of_finished_trips[i].ata
75
+
76
+ else:
77
+ if list_of_finished_trips[i - 1].is_copy is True:
78
+ earliest_time = list_of_finished_trips[i - 1].ata
79
+ if list_of_finished_trips[i + 1].is_copy is True:
80
+ latest_time = list_of_finished_trips[i + 1].atd
81
+
82
+ return finished_schedules, earliest_time, latest_time
83
+
84
+
85
+ def generate_vehicle_events(
86
+ dict_of_events,
87
+ current_vehicle: SimpleVehicle,
88
+ virtual_waiting_area_id: int,
89
+ earliest_time: datetime.datetime,
90
+ latest_time: datetime.datetime,
91
+ ) -> None:
92
+ """
93
+ This function generates and ordered dictionary storing the data related to an event.
94
+
95
+ It returns a dictionary. The keys are the start times of the
96
+ events. The values are also dictionaries containing:
97
+ - type: The type of the event.
98
+ - end: The end time of the event.
99
+ - area: The area id of the event.
100
+ - slot: The slot id of the event.
101
+ - id: The id of the event-related process.
102
+
103
+ For trips, only the type is stored.
104
+
105
+ For waiting events, the slot is not stored for now.
106
+
107
+ :param current_vehicle: a :class:`eflips.depot.simple_vehicle.SimpleVehicle` object.
108
+
109
+ :param virtual_waiting_area_id: the id of the virtual waiting area. Vehicles waiting for the first process will park here.
110
+
111
+ :param earliest_time: the earliest relevant time of the current vehicle. Any events earlier than this will not be
112
+ handled.
113
+
114
+ :param latest_time: the latest relevant time of the current vehicle. Any events later than this will not be handled.
115
+
116
+ :return: None. The results are added to the dictionary.
117
+ """
118
+
119
+ logger = logging.getLogger(__name__)
120
+
121
+ # For convenience
122
+ area_log = current_vehicle.logger.loggedData["dwd.current_area"]
123
+ slot_log = current_vehicle.logger.loggedData["dwd.current_slot"]
124
+ waiting_log = current_vehicle.logger.loggedData["area_waiting_time"]
125
+
126
+ # Handling waiting events
127
+ waiting_log_timekeys = sorted(waiting_log.keys())
128
+
129
+ for idx in range(len(waiting_log_timekeys)):
130
+ waiting_end_time = waiting_log_timekeys[idx]
131
+
132
+ # Only extract events if the time is within the upper mentioned range
133
+
134
+ if earliest_time <= waiting_end_time <= latest_time:
135
+ waiting_info = waiting_log[waiting_end_time]
136
+
137
+ if waiting_info["waiting_time"] == 0:
138
+ continue
139
+
140
+ logger.info(
141
+ f"Vehicle {current_vehicle.ID} has been waiting for {waiting_info['waiting_time']} seconds. "
142
+ )
143
+
144
+ start_time = waiting_end_time - waiting_info["waiting_time"]
145
+
146
+ if waiting_info["area"] == waiting_log[waiting_log_timekeys[0]]["area"]:
147
+ # if the vehicle is waiting for the first process, put it in the virtual waiting area
148
+ waiting_area_id = virtual_waiting_area_id
149
+ else:
150
+ # If the vehicle is waiting for other processes,
151
+ # put it in the area of the prodecessor process of the waited process.
152
+ waiting_area_id = waiting_log[waiting_log_timekeys[idx - 1]]["area"]
153
+
154
+ dict_of_events[start_time] = {
155
+ "type": "Standby",
156
+ "end": waiting_end_time,
157
+ "area": waiting_area_id,
158
+ "is_waiting": True,
159
+ }
160
+
161
+ # Create a list of battery log in order of time asc. Convenient for looking up corresponding soc
162
+
163
+ for time_stamp, process_log in current_vehicle.logger.loggedData[
164
+ "dwd.active_processes_copy"
165
+ ].items():
166
+ if earliest_time <= time_stamp <= latest_time:
167
+ num_process = len(process_log)
168
+ if num_process == 0:
169
+ # A departure happens and this trip should already be stored in the dictionary
170
+ pass
171
+ else:
172
+ for process in process_log:
173
+ current_area = area_log[time_stamp]
174
+ current_slot = slot_log[time_stamp]
175
+
176
+ if current_area is None or current_slot is None:
177
+ raise ValueError(
178
+ f"For process {process.ID} Area and slot should not be None."
179
+ )
180
+
181
+ match process.status:
182
+ case ProcessStatus.COMPLETED | ProcessStatus.CANCELLED:
183
+ assert (
184
+ len(process.starts) == 1 and len(process.ends) == 1
185
+ ), (
186
+ f"Current process {process.ID} is completed and should only contain one start and "
187
+ f"one end time."
188
+ )
189
+
190
+ if process.dur > 0:
191
+ # Valid duration
192
+ dict_of_events[time_stamp] = {
193
+ "type": type(process).__name__,
194
+ "end": process.ends[0],
195
+ "area": current_area.ID,
196
+ "slot": current_slot,
197
+ "id": process.ID,
198
+ }
199
+ else:
200
+ # Duration is 0
201
+ assert current_area.issink is True, (
202
+ f"A process with no duration could only "
203
+ f"happen in the last area before dispatched"
204
+ )
205
+ if (
206
+ time_stamp in dict_of_events.keys()
207
+ and "end" in dict_of_events[time_stamp].keys()
208
+ ):
209
+ start_this_event = dict_of_events[time_stamp]["end"]
210
+ if start_this_event in dict_of_events.keys():
211
+ if (
212
+ dict_of_events[start_this_event]["type"]
213
+ == "Trip"
214
+ ):
215
+ logger.info(
216
+ f"Vehicle {current_vehicle.ID} must depart immediately after charged. "
217
+ f"Thus there will be no STANDBY_DEPARTURE event."
218
+ )
219
+
220
+ else:
221
+ raise ValueError(
222
+ f"There is already an event "
223
+ f"{dict_of_events[start_this_event]} at {start_this_event}."
224
+ )
225
+
226
+ continue
227
+
228
+ dict_of_events[start_this_event] = {
229
+ "type": type(process).__name__,
230
+ "area": current_area.ID,
231
+ "slot": current_slot,
232
+ "id": process.ID,
233
+ }
234
+
235
+ case ProcessStatus.IN_PROGRESS:
236
+ assert (
237
+ len(process.starts) == 1 and len(process.ends) == 0
238
+ ), f"Current process {process.ID} is marked IN_PROGRESS, but has an end."
239
+
240
+ if current_area is None or current_slot is None:
241
+ raise ValueError(
242
+ f"For process {process.ID} Area and slot should not be None."
243
+ )
244
+
245
+ if process.dur > 0:
246
+ # Valid duration
247
+ dict_of_events[time_stamp] = {
248
+ "type": type(process).__name__,
249
+ "end": process.etc,
250
+ "area": current_area.ID,
251
+ "slot": current_slot,
252
+ "id": process.ID,
253
+ }
254
+ else:
255
+ raise NotImplementedError(
256
+ "We believe this should never happen. If it happens, handle it here."
257
+ )
258
+
259
+ # The following ProcessStatus possibly only happen while the simulation is running,
260
+ # not in the results
261
+ case ProcessStatus.WAITING:
262
+ raise NotImplementedError(
263
+ f"Current process {process.ID} is waiting. Not implemented yet."
264
+ )
265
+
266
+ case ProcessStatus.NOT_STARTED:
267
+ raise NotImplementedError(
268
+ f"Current process {process.ID} is not started. Not implemented yet."
269
+ )
270
+
271
+ case _:
272
+ raise ValueError(
273
+ f"Invalid process status {process.status} for process {process.ID}."
274
+ )
275
+
276
+
277
+ def complete_standby_departure_events(
278
+ dict_of_events: Dict, latest_time: datetime.datetime
279
+ ) -> None:
280
+ """
281
+ This function completes the standby departure events by adding an end time to each standby departure event.
282
+
283
+ :param dict_of_events: a dictionary containing the events of a vehicle. The keys are the start times of the events.
284
+
285
+ :param latest_time: the latest relevant time of the current vehicle. Any events later than this will not be handled.
286
+
287
+ :return: None. The results are added to the dictionary.
288
+ """
289
+ for i in range(len(dict_of_events.keys())):
290
+ time_keys = sorted(dict_of_events.keys())
291
+
292
+ process_dict = dict_of_events[time_keys[i]]
293
+ if "end" not in process_dict and process_dict["type"] != "Trip":
294
+ # End time of a standby_departure will be the start of the following trip
295
+ if i == len(time_keys) - 1:
296
+ # The event reaches simulation end
297
+ end_time = latest_time
298
+ else:
299
+ end_time = time_keys[i + 1]
300
+
301
+ process_dict["end"] = end_time
302
+
303
+
304
+ def add_soc_to_events(dict_of_events, battery_log) -> None:
305
+ """
306
+ This function completes the soc of each event by looking up the battery log.
307
+
308
+ :param dict_of_events: a dictionary containing the events of a vehicle. The keys are the start times of the events.
309
+
310
+ :param battery_log: a list of battery logs of a vehicle.
311
+
312
+ :return: None. The results are added to the dictionary.
313
+ """
314
+ battery_log_list = []
315
+ for log in battery_log:
316
+ battery_log_list.append((log.t, log.energy / log.energy_real))
317
+
318
+ time_keys = sorted(dict_of_events.keys())
319
+ for i in range(len(time_keys)):
320
+ # Get soc
321
+ soc_start = None
322
+ soc_end = None
323
+ start_time = time_keys[i]
324
+ process_dict = dict_of_events[time_keys[i]]
325
+ for j in range(len(battery_log_list)):
326
+ # Access the correct battery log according to time since there is only one battery log for each time
327
+ log = battery_log_list[j]
328
+
329
+ if process_dict["type"] != "Trip":
330
+ if log[0] == start_time:
331
+ soc_start = log[1]
332
+ if log[0] == process_dict["end"]:
333
+ soc_end = log[1]
334
+ if log[0] < start_time < battery_log_list[j + 1][0]:
335
+ soc_start = log[1]
336
+ if log[0] < process_dict["end"] < battery_log_list[j + 1][0]:
337
+ soc_end = log[1]
338
+
339
+ if soc_start is not None:
340
+ soc_start = min(soc_start, 1) # so
341
+ process_dict["soc_start"] = soc_start
342
+ if soc_end is not None:
343
+ soc_end = min(soc_end, 1) # soc should not exceed 1
344
+ process_dict["soc_end"] = soc_end
345
+
346
+ else:
347
+ continue
348
+
349
+
350
+ def add_events_into_database(
351
+ db_vehicle, dict_of_events, session, scenario, simulation_start_time
352
+ ) -> None:
353
+ """
354
+ This function generates :class:`eflips.model.Event` objects from the dictionary of events and adds them into the.
355
+
356
+ database.
357
+
358
+ :param db_vehicle: vehicle object in the database
359
+
360
+ :param dict_of_events: dictionary containing the events of a vehicle. The keys are the start times of the events.
361
+
362
+ :param session: a :class:`sqlalchemy.orm.Session` object for database connection.
363
+
364
+ :param scenario: the current simulated scenario
365
+
366
+ :param simulation_start_time: simulation start time in :class:`datetime.datetime` format
367
+
368
+ :return: None. The results are added to the database.
369
+ """
370
+ logger = logging.getLogger(__name__)
371
+
372
+ for start_time, process_dict in dict_of_events.items():
373
+ # Generate EventType
374
+ match process_dict["type"]:
375
+ case "Serve":
376
+ event_type = EventType.SERVICE
377
+ case "Charge":
378
+ event_type = EventType.CHARGING_DEPOT
379
+ case "Standby":
380
+ if (
381
+ "is_waiting" in process_dict.keys()
382
+ and process_dict["is_waiting"] is True
383
+ ):
384
+ event_type = EventType.STANDBY
385
+ else:
386
+ event_type = EventType.STANDBY_DEPARTURE
387
+ case "Precondition":
388
+ event_type = EventType.PRECONDITIONING
389
+ case "Trip":
390
+ continue
391
+ case _:
392
+ raise ValueError(
393
+ 'Invalid process type %s. Valid process types are "Serve", "Charge", '
394
+ '"Standby", "Precondition"'
395
+ )
396
+
397
+ if process_dict["end"] == start_time:
398
+ logger.warning("Refusing to create an event with zero duration.")
399
+ continue
400
+
401
+ current_event = Event(
402
+ scenario=scenario,
403
+ vehicle_type_id=db_vehicle.vehicle_type_id,
404
+ vehicle=db_vehicle,
405
+ station_id=None,
406
+ area_id=int(process_dict["area"]),
407
+ subloc_no=int(process_dict["slot"]) - 1
408
+ if "slot" in process_dict.keys()
409
+ else 00,
410
+ trip_id=None,
411
+ time_start=timedelta(seconds=start_time) + simulation_start_time,
412
+ time_end=timedelta(seconds=process_dict["end"]) + simulation_start_time,
413
+ soc_start=process_dict["soc_start"]
414
+ if process_dict["soc_start"] is not None
415
+ else process_dict["soc_end"],
416
+ soc_end=process_dict["soc_end"]
417
+ if process_dict["soc_end"] is not None
418
+ else process_dict["soc_start"], # if only one battery log is found,
419
+ # then this is not an event with soc change
420
+ event_type=event_type,
421
+ description=process_dict["id"] if "id" in process_dict.keys() else None,
422
+ timeseries=None,
423
+ )
424
+
425
+ session.add(current_event)
426
+
427
+
428
+ def update_vehicle_in_rotation(session, scenario, list_of_assigned_schedules) -> None:
429
+ """
430
+ This function updates the vehicle id assigned to the rotations and deletes the events that are not depot events.
431
+
432
+ :param session: a :class:`sqlalchemy.orm.Session` object for database connection.
433
+ :param scenario: the current simulated scenario
434
+ :param list_of_assigned_schedules: a list of tuples containing the rotation id and the vehicle id.
435
+ :return: None. The results are added to the database.
436
+ """
437
+ # New rotation assignment
438
+ for schedule_id, vehicle_id in list_of_assigned_schedules:
439
+ # Get corresponding old vehicle id
440
+ session.query(Rotation).filter(Rotation.id == schedule_id).update(
441
+ {"vehicle_id": vehicle_id}, synchronize_session="auto"
442
+ )
443
+
444
+ # Delete all non-depot events
445
+ session.query(Event).filter(
446
+ Event.scenario == scenario,
447
+ Event.trip_id.isnot(None) | Event.station_id.isnot(None),
448
+ ).delete(synchronize_session="auto")
449
+
450
+ session.flush()
451
+
452
+ # Delete all vehicles without rotations
453
+ vehicle_assigned_sq = (
454
+ session.query(Rotation.vehicle_id)
455
+ .filter(Rotation.scenario == scenario)
456
+ .distinct()
457
+ .subquery()
458
+ )
459
+
460
+ session.query(Vehicle).filter(Vehicle.scenario == scenario).filter(
461
+ Vehicle.id.not_in(select(vehicle_assigned_sq))
462
+ ).delete()
463
+
464
+ session.flush()
465
+
466
+
467
+ def update_waiting_events(session, scenario, waiting_area_id) -> None:
468
+ """
469
+ This function evaluates the capacity of waiting area and assigns the waiting events to corresponding slots in the.
470
+
471
+ waiting area.
472
+
473
+ :param session: a :class:`sqlalchemy.orm.Session` object for database connection.
474
+
475
+ :param scenario: the current simulated scenario.
476
+
477
+ :param waiting_area_id: id of the waiting area.
478
+
479
+ :raise ValueError: if the waiting area capacity is less than the peak waiting occupancy.
480
+
481
+ :return: None. The results are added to the database.
482
+ """
483
+ logger = logging.getLogger(__name__)
484
+
485
+ # Process all the STANDBY (waiting) events #
486
+ all_waiting_starts = (
487
+ session.query(Event)
488
+ .filter(
489
+ Event.scenario_id == scenario.id,
490
+ Event.event_type == EventType.STANDBY,
491
+ Event.area_id == waiting_area_id,
492
+ )
493
+ .all()
494
+ )
495
+
496
+ all_waiting_ends = (
497
+ session.query(Event)
498
+ .filter(
499
+ Event.scenario_id == scenario.id,
500
+ Event.event_type == EventType.STANDBY,
501
+ Event.area_id == waiting_area_id,
502
+ )
503
+ .all()
504
+ )
505
+
506
+ assert len(all_waiting_starts) == len(
507
+ all_waiting_ends
508
+ ), f"Number of waiting events starts {len(all_waiting_starts)} is not equal to the number of waiting event ends"
509
+
510
+ if len(all_waiting_starts) == 0:
511
+ logger.info(
512
+ "No waiting events found. The depot has enough capacity for waiting. Change the waiting area capacity to 10 as buffer."
513
+ )
514
+
515
+ session.query(Area).filter(Area.id == waiting_area_id).update(
516
+ {"capacity": 10}, synchronize_session="auto"
517
+ )
518
+
519
+ return
520
+
521
+ list_waiting_timestamps = []
522
+ for waiting_start in all_waiting_starts:
523
+ list_waiting_timestamps.append(
524
+ {"timestamp": waiting_start.time_start, "event": (waiting_start.id, 1)}
525
+ )
526
+
527
+ for waiting_end in all_waiting_ends:
528
+ list_waiting_timestamps.append(
529
+ {"timestamp": waiting_end.time_end, "event": (waiting_end.id, -1)}
530
+ )
531
+
532
+ list_waiting_timestamps.sort(key=lambda x: x["timestamp"])
533
+ start_and_end_records = [wt["event"][1] for wt in list_waiting_timestamps]
534
+
535
+ peak_waiting_occupancy = max(list(itertools.accumulate(start_and_end_records)))
536
+
537
+ # Assuming that there is only one waiting area in each depot
538
+
539
+ waiting_area_id = all_waiting_starts[0].area_id
540
+ waiting_area = session.query(Area).filter(Area.id == waiting_area_id).first()
541
+ if waiting_area.capacity > peak_waiting_occupancy:
542
+ logger.info(
543
+ f"Current waiting area capacity {waiting_area.capacity} "
544
+ f"is greater than the peak waiting occupancy. Updating the capacity to {peak_waiting_occupancy}."
545
+ )
546
+ session.query(Area).filter(Area.id == waiting_area_id).update(
547
+ {"capacity": peak_waiting_occupancy}, synchronize_session="auto"
548
+ )
549
+ session.flush()
550
+ elif waiting_area.capacity < peak_waiting_occupancy:
551
+ raise ValueError(
552
+ f"Waiting area capacity is less than the peak waiting occupancy. "
553
+ f"Waiting area capacity: {waiting_area.capacity}, peak waiting occupancy: {peak_waiting_occupancy}."
554
+ )
555
+ else:
556
+ pass
557
+
558
+ session.flush()
559
+
560
+ # Update waiting slots
561
+ virtual_waiting_area = [None] * peak_waiting_occupancy
562
+ for wt in list_waiting_timestamps:
563
+ # check in
564
+ if wt["event"][1] == 1:
565
+ for i in range(len(virtual_waiting_area)):
566
+ if virtual_waiting_area[i] is None:
567
+ virtual_waiting_area[i] = wt["event"][0]
568
+ session.query(Event).filter(Event.id == wt["event"][0]).update(
569
+ {"subloc_no": i}, synchronize_session="auto"
570
+ )
571
+ break
572
+ # check out
573
+ else:
574
+ for i in range(len(virtual_waiting_area)):
575
+ if virtual_waiting_area[i] == wt["event"][0]:
576
+ current_waiting_event = (
577
+ session.query(Event).filter(Event.id == wt["event"][0]).first()
578
+ )
579
+ assert current_waiting_event.subloc_no == i, (
580
+ f"Subloc number of the event {current_waiting_event.id} is not equal to the index of the "
581
+ f"event in the virtual waiting area."
582
+ )
583
+ virtual_waiting_area[i] = None
584
+ break
585
+
586
+ session.flush()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: eflips-depot
3
- Version: 4.3.17
3
+ Version: 4.3.19
4
4
  Summary: Depot Simulation for eFLIPS
5
5
  Home-page: https://github.com/mpm-tu-berlin/eflips-depot
6
6
  License: AGPL-3.0-or-later
@@ -12,6 +12,7 @@ Classifier: Programming Language :: Python :: 3
12
12
  Classifier: Programming Language :: Python :: 3.10
13
13
  Classifier: Programming Language :: Python :: 3.11
14
14
  Classifier: Programming Language :: Python :: 3.12
15
+ Classifier: Programming Language :: Python :: 3.13
15
16
  Requires-Dist: eflips (>=0.1.3,<0.2.0)
16
17
  Requires-Dist: eflips-model (>=5.0.0,<6.0.0)
17
18
  Requires-Dist: pandas (>=2.1.4,<3.0.0)
@@ -1,8 +1,9 @@
1
1
  eflips/depot/__init__.py,sha256=n7jte8R6j_Ad4Mp4hkklKwil5r8u8Q_SbXrCC-nf5jM,1556
2
- eflips/depot/api/__init__.py,sha256=CHmoF0TGEUuws-F6TglG2Kd8L3T-4j0PpUsPI7XbGYI,95668
2
+ eflips/depot/api/__init__.py,sha256=lEGFfWXFZsq49jY7CUVFkXjYksxRT9exILPEglTnK1E,57457
3
3
  eflips/depot/api/defaults/default_settings.json,sha256=0eUDTw_rtLQFvthP8oJL93iRXlmAOravAg-4qqGMQAY,5375
4
4
  eflips/depot/api/private/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
- eflips/depot/api/private/depot.py,sha256=ekKa06bv_yVwkfPbLdnCLQF-0DaxpXQHuxUFqlH1xYE,21486
5
+ eflips/depot/api/private/depot.py,sha256=Fan7vyVDNcQmuKxoETI6FqLEYII-TJlSor2wiT79zNc,35344
6
+ eflips/depot/api/private/results_to_database.py,sha256=HrElB_ctOZX-Jir4uab76ii26H2LOdwpFTCmNmLawHg,24223
6
7
  eflips/depot/api/private/smart_charging.py,sha256=bgxBJ-Lytd2JXN_fm8wb268wbRDrwur_zfEzj0cnhu4,13052
7
8
  eflips/depot/api/private/util.py,sha256=Ye-WXNzHcNfunFijK7FCIU3AiCuMg83KnEhnKbtlZu8,17242
8
9
  eflips/depot/configuration.py,sha256=Op3hlir-dEN7yHr0kTqbYANoCBKFWK6uKOv3NJl8w_w,35678
@@ -35,7 +36,7 @@ eflips/depot/simulation.py,sha256=ee0qTzOzG-8ybN36ie_NJallXfC7jUaS9JZvaYFziLs,10
35
36
  eflips/depot/smart_charging.py,sha256=C3BYqzn2-OYY4ipXm0ETtavbAM9QXZMYULBpVoChf0E,54311
36
37
  eflips/depot/standalone.py,sha256=VxcTzBaB67fNJUMmjPRwKXjhqTy6oQ41Coote2LvAmk,22338
37
38
  eflips/depot/validation.py,sha256=TIuY7cQtEJI4H2VVMSuY5IIVkacEEZ67weeMuY3NSAM,7097
38
- eflips_depot-4.3.17.dist-info/LICENSE.md,sha256=KB4XTk1fPHjtZCYDyPyreu6h1LVJVZXYg-5vePcWZAc,34143
39
- eflips_depot-4.3.17.dist-info/METADATA,sha256=aibdGSHQpT-gSweuPzuxx7ppgXt1ssY3jLXF0USsj_I,5840
40
- eflips_depot-4.3.17.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
41
- eflips_depot-4.3.17.dist-info/RECORD,,
39
+ eflips_depot-4.3.19.dist-info/LICENSE.md,sha256=KB4XTk1fPHjtZCYDyPyreu6h1LVJVZXYg-5vePcWZAc,34143
40
+ eflips_depot-4.3.19.dist-info/METADATA,sha256=jeE1B9_GHvTXPKbsiqrqK3RQFLQMea9oD99gJ7tc_AM,5891
41
+ eflips_depot-4.3.19.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
42
+ eflips_depot-4.3.19.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: poetry-core 1.9.0
2
+ Generator: poetry-core 1.9.1
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any