Battery Charging Station
This example highlights some interesting differences between hades and the wonderful simpy based on their Shared Resources example.
The key things to note are that the queue of waiting cars happens in a process rather than making use of a shared resource.
This means the state of the battery charging station contains some useful information (and the state can be interrogated after the simulation is run etc), but results in slightly less terse code and more logic within it.
# Copyright 2023 Brit Group Services Ltd.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import asyncio
from hades import Event, Hades, NotificationResponse, PredefinedEventAdder, Process
class CarArrives(Event):
car_id: int
class CarStartsCharging(Event):
car_id: int
class CarLeaves(Event):
car_id: int
class BatteryChargingStation(Process):
def __init__(self, charging_duration: int):
super().__init__()
self.charging_duration = charging_duration
self.currently_charging = set()
self.waiting_cars = []
async def notify(self, event: Event) -> NotificationResponse:
match event:
case CarArrives(t=t, car_id=car_id):
print(f"Car {car_id} arriving at {t}")
if len(self.currently_charging) < 2:
self.currently_charging.add(car_id)
self.add_event(CarStartsCharging(t=t, car_id=car_id))
else:
self.waiting_cars.append(car_id)
return NotificationResponse.ACK
case CarStartsCharging(t=t, car_id=car_id):
print(f"Car {car_id} starting to charge at {t}")
self.add_event(CarLeaves(t=t + self.charging_duration, car_id=car_id))
return NotificationResponse.ACK
case CarLeaves(t=t, car_id=car_id):
print(f"Car {car_id} leaving the bcs at {t}")
self.currently_charging.remove(car_id)
if self.waiting_cars:
next_car = self.waiting_cars.pop(0)
self.currently_charging.add(next_car)
self.add_event(CarStartsCharging(t=t, car_id=next_car))
return NotificationResponse.ACK
return NotificationResponse.NO_ACK
async def bcs():
hades = Hades()
bcs = BatteryChargingStation(charging_duration=5)
hades.register_process(bcs)
# Creating events for cars arriving at the battery charging station
events: list[CarArrives] = [CarArrives(t=2 * i, car_id=i) for i in range(4)]
event_adder = PredefinedEventAdder(predefined_events=events, name="car arrivals")
hades.register_process(event_adder)
await hades.run()
if __name__ == "__main__":
asyncio.run(bcs())
Output¶
The output will look the same as in the simpy example but is arrived at in a different way!
Car 0 arriving at 0
Car 0 starting to charge at 0
Car 1 arriving at 2
Car 1 starting to charge at 2
Car 2 arriving at 4
Car 0 leaving the bcs at 5
Car 2 starting to charge at 5
Car 3 arriving at 6
Car 1 leaving the bcs at 7
Car 3 starting to charge at 7
Car 2 leaving the bcs at 10
Car 3 leaving the bcs at 12