class EventLoop(object): KEEP_ALIVE = 60 class TOPIC(object): PUBLISH = "pub_event_loop" SUBSCRIBE = "sub_event_loop" def __init__(self, _id=None): self.event_loop_id = _id if _id is None: self.event_loop_id = str(uuid()) self.__subscribeTopic = Topic() self.__subscribeTopic.set_id(self.event_loop_id) self.__subscribeTopic.set_root(EventLoop.TOPIC.SUBSCRIBE) self.__subscribeTopic.set_message(event_loop_message) self.__publishTopic = Topic() self.__publishTopic.set_id(self.event_loop_id) self.__publishTopic.set_root(EventLoop.TOPIC.PUBLISH) self.__publishTopic.set_message(event_loop_message) self.__subscribers = {} self.__publishers = {} self.__client = None self.__main_loop = None self.__pid = os.getpid() self.set_subscriber(self.__subscribeTopic.private) self.__on_message_functions = [] self.__user_data = None self.__user_will = None def __del__(self): if self.__client is not None: message = self.__publishTopic.get_template() message["action"] = "disconnect" message["pid"] = self.__pid payload = self.__publishTopic.serialize(message) self.publish(self.__publishTopic.private, payload) self.__client.disconnect() def set_subscriber(self, topic): self.__subscribers[str(uuid())] = {"topic": topic} def set_user_data(self, user_data): self.__user_data = user_data def add_on_message_function(self, on_message_function): self.__on_message_functions.append(on_message_function) def set_main_loop(self, main_loop): self.__main_loop = main_loop def set_will(self, topic, payload): self.__user_will = {"topic": topic, "payload": payload} def publish(self, topic, payload, qos=0, retain=False): # payload = self.__subscribeTopic.serialize(message) self.__client.publish(topic, payload=payload, qos=qos, retain=retain) def __on_message(self, client, userdata, message_data): payload = message_data.payload.decode("utf-8") if self.__subscribeTopic.root in message_data.topic and \ self.__subscribeTopic.get_id(message_data.topic) == self.event_loop_id: message = self.__subscribeTopic.unserialize(payload) if message["action"] == "start": print(self.__subscribeTopic.root, message) if message["action"] == "kill": print(self.__subscribeTopic.root, message) self.end() if message["action"] == "check": print(self.__subscribeTopic.root, message) self.__check() for onMessageFunction in self.__on_message_functions: onMessageFunction(client, userdata, message_data.topic, payload) return True def connect(self, host, port): self.__client = mqtt.Client(protocol=mqtt.MQTTv311, userdata=self.__user_data) will = self.__user_will print(will) if will is None: message = self.__publishTopic.get_template() message["action"] = "will" message["pid"] = self.__pid payload = self.__publishTopic.serialize(message) will = {"topic": self.__publishTopic.private, "payload": payload} self.__client.will_set(will["topic"], payload=will["payload"], qos=2, retain=False) self.__client.on_message = self.__on_message self.__client.connect(host=host, port=port, keepalive=EventLoop.KEEP_ALIVE) def start(self, host="localhost", port=1883): self.connect(host, port) for subscriber in self.__subscribers.values(): self.__client.subscribe(subscriber["topic"]) message = self.__publishTopic.get_template() message["time"] = str(int(time())) message["action"] = "start" message["pid"] = self.__pid payload = self.__publishTopic.serialize(message) self.publish(self.__publishTopic.private, payload) if self.__main_loop is None: self.__client.loop_forever() else: self.__client.loop_start() self.__main_loop() def end(self): self.__client.loop_stop() self.__client.disconnect() os.kill(self.__pid, SIGKILL) def __check(self): # todo: main_loop zombie message = self.__publishTopic.get_template() message["time"] = str(int(time())) message["action"] = "ok" message["pid"] = self.__pid payload = self.__publishTopic.serialize(message) self.publish(self.__publishTopic.private, payload) def get_pid(self): return self.__pid
class FleetManager(EventLoop): class ACTION(object): PUBLISH_RELATIONS = "pub_relations" class TOPIC(object): PUBLISH = "pub_fleet_manager" SUBSCRIBE = "sub_fleet_manager" def __init__(self, waypoint, arrow, route): super().__init__() self.topicUserPublish = Topic() self.topicUserPublish.set_root(User.TOPIC.PUBLISH) self.topicUserPublish.set_message(user_message) self.topicUserSubscribe = Topic() self.topicUserSubscribe.set_root(User.TOPIC.SUBSCRIBE) self.topicUserSubscribe.set_message(user_message) self.topicVehiclePublish = Topic() self.topicVehiclePublish.set_root(Vehicle.TOPIC.PUBLISH) self.topicVehiclePublish.set_message(vehicle_message) self.topicVehicleSubscribe = Topic() self.topicVehicleSubscribe.set_root(Vehicle.TOPIC.SUBSCRIBE) self.topicVehicleSubscribe.set_message(vehicle_message) self.topicTrafficSignalPublish = Topic() self.topicTrafficSignalPublish.set_root(TrafficSignal.TOPIC.PUBLISH) self.topicTrafficSignalPublish.set_message(traffic_signal_message) self.topicFleetManagerPublish = Topic() self.topicFleetManagerPublish.set_id(self.event_loop_id) self.topicFleetManagerPublish.set_root(FleetManager.TOPIC.PUBLISH) self.topicFleetManagerPublish.set_message(fleet_manager_message) self.topicFleetManagerSubscribe = Topic() self.topicFleetManagerSubscribe.set_id(self.event_loop_id) self.topicFleetManagerSubscribe.set_root(FleetManager.TOPIC.SUBSCRIBE) self.topicFleetManagerSubscribe.set_message(fleet_manager_message) self.waypoint = waypoint self.arrow = arrow self.route = route self.users = {} self.vehicles = {} self.traffic_signals = {} self.relations = {} # vehicle_id -> user_id, user_id -> vehicle_id self.add_on_message_function(self.update_user_status) self.add_on_message_function(self.update_vehicle_status) self.add_on_message_function(self.update_traffic_signal_status) self.add_on_message_function(self.response_request) self.set_subscriber(self.topicUserPublish.all) self.set_subscriber(self.topicVehiclePublish.all) self.set_subscriber(self.topicTrafficSignalPublish.all) self.set_subscriber(self.topicFleetManagerSubscribe.all) def update_user_status(self, _client, _userdata, topic, payload): # print("update_user_status", topic) if self.topicUserPublish.root in topic: user_id = self.topicUserPublish.get_id(topic) message = self.topicUserPublish.unserialize(payload) if message["state"] == User.STATE.LOGIN: # print("user", User.STATE.LOGIN) # todo: move to dispatcher class self.dispatch(user_id, message) elif message["state"] == User.STATE.WAITING: pass # print("user", User.STATE.WAITING) elif message["state"] == User.STATE.GETTING_ON: pass # print("user", User.STATE.GETTING_ON) elif message["state"] == User.STATE.GOT_ON: # print("user", User.STATE.GOT_ON) vehicle_id = self.relations[user_id] self.vehicles[vehicle_id]["schedules"][0][ "action"] = Vehicle.ACTION.MOVE payload = self.topicVehicleSubscribe.serialize( {"schedules": self.vehicles[vehicle_id]["schedules"]}) self.publish( self.topicVehicleSubscribe.root + "/" + vehicle_id + "/schedules", payload) elif message["state"] == User.STATE.MOVING: pass # print("user", User.STATE.MOVING) elif message["state"] == User.STATE.GETTING_OUT: pass # print("user", User.STATE.GETTING_OUT) elif message["state"] == User.STATE.GOT_OUT: pass # print("user", User.STATE.GOT_OUT) else: print("user", message["state"]) self.users[user_id] = message def update_vehicle_status(self, _client, _userdata, topic, payload): if self.topicVehiclePublish.root in topic: vehicle_id = self.topicVehiclePublish.get_id(topic) message = self.topicVehiclePublish.unserialize(payload) # print("update_vehicle_status", topic, message["state"]) if vehicle_id in self.relations: prev_state = self.vehicles[vehicle_id]["state"] if message["state"] == SimTaxi.STATE.MOVE_TO_USER: # print("vehicle", SimTaxi.STATE.MOVE_TO_USER) if prev_state == SimTaxi.STATE.STANDBY: user_id = self.relations[vehicle_id] self.users[user_id]["schedules"][0][ "action"] = User.ACTION.WAIT self.publish( self.topicUserSubscribe.root + "/" + user_id + "/schedules", self.topicUserSubscribe.serialize({ "schedules": self.users[user_id]["schedules"] })) elif message["state"] == SimTaxi.STATE.STOP_FOR_PICKING_UP: # print("vehicle", SimTaxi.STATE.STOP_FOR_PICKING_UP) if prev_state == SimTaxi.STATE.MOVE_TO_USER: # print("vehicle", SimTaxi.STATE.STOP_FOR_PICKING_UP, SimTaxi.STATE.MOVE_TO_USER) user_id = self.relations[vehicle_id] self.users[user_id]["schedules"][0][ "action"] = User.ACTION.GET_ON self.publish( self.topicUserSubscribe.root + "/" + user_id + "/schedules", self.topicUserSubscribe.serialize({ "schedules": self.users[user_id]["schedules"] })) elif message[ "state"] == SimTaxi.STATE.MOVE_TO_USER_DESTINATION: # print("vehicle", SimTaxi.STATE.MOVE_TO_USER_DESTINATION) if prev_state == SimTaxi.STATE.STOP_FOR_PICKING_UP: # print("vehicle", SimTaxi.STATE.MOVE_TO_USER_DESTINATION, SimTaxi.STATE.STOP_FOR_PICKING_UP) user_id = self.relations[vehicle_id] self.users[user_id]["schedules"][0][ "event"] = User.EVENT.MOVE_VEHICLE self.publish( self.topicUserSubscribe.root + "/" + user_id + "/event", self.topicUserSubscribe.serialize( {"event": User.EVENT.MOVE_VEHICLE})) elif message["state"] == SimTaxi.STATE.STOP_FOR_DISCHARGING: # print("vehicle", SimTaxi.STATE.STOP_FOR_DISCHARGING) if prev_state == SimTaxi.STATE.MOVE_TO_USER_DESTINATION: user_id = self.relations[vehicle_id] self.users[user_id]["schedules"][0][ "action"] = User.ACTION.GET_OUT self.publish( self.topicUserSubscribe.root + "/" + user_id + "/schedules", self.topicUserSubscribe.serialize({ "schedules": self.users[user_id]["schedules"] })) elif message["state"] == SimTaxi.STATE.MOVE_TO_STANDBY: pass # print("vehicle", SimTaxi.STATE.MOVE_TO_STANDBY) elif message["state"] == SimTaxi.STATE.STANDBY: pass # print("vehicle", SimTaxi.STATE.STANDBY) else: print("vehicle", message["state"]) # vehicleSchedule = vehicle.pop("schedule") if vehicle_id not in self.vehicles: # print("set vehicle", vehicle_id, message["name"]) self.vehicles[vehicle_id] = message else: # print("update vehicle", vehicle_id, message["name"]) self.vehicles[vehicle_id].update(message) def update_traffic_signal_status(self, _client, _userdata, topic, payload): if self.topicTrafficSignalPublish.root in topic: message = self.topicTrafficSignalPublish.unserialize(payload) for route in message["routes"]: self.traffic_signals[route["route_code"]] = route def response_request(self, _client, _userdata, topic, payload): if self.topicFleetManagerSubscribe.root in topic: message = self.topicFleetManagerSubscribe.unserialize(payload) if message["action"] == FleetManager.ACTION.PUBLISH_RELATIONS: self.publish_relations() def get_dispatchable_vehicles(self): return dict( filter(lambda x: x[1]["state"] in [SimTaxi.STATE.STANDBY], self.vehicles.items())) def dispatch(self, user_id, user_status): start_point = { "arrow_code": self.arrow.get_arrow_codes_from_waypoint_id( user_status["schedules"][0]["start"]["waypoint_id"])[0], "waypoint_id": user_status["schedules"][0]["start"]["waypoint_id"], } vehicles = self.get_dispatchable_vehicles() if len(vehicles) == 0: print("no dispatchable vehicles") return goal_points = [] for vehicle_id, goal_waypoint_id in map( lambda x: (x[0], x[1]["location"]["waypoint_id"]), vehicles.items()): goal_points.append({ "goal_id": vehicle_id, "arrow_code": self.arrow.get_arrow_codes_from_waypoint_id(goal_waypoint_id) [0], "waypoint_id": goal_waypoint_id, }) routes = self.route.get_shortest_routes(start_point, goal_points, reverse=True) if len(routes) == 0: print("no pick_up_route") return pick_up_route = min(routes.items(), key=lambda x: x[1]["cost"])[1] vehicle_id = pick_up_route["goal_id"] start_point = { "arrow_code": self.arrow.get_arrow_codes_from_waypoint_id( user_status["schedules"][0]["start"]["waypoint_id"])[0], "waypoint_id": user_status["schedules"][0]["start"]["waypoint_id"], } goal_points = [{ "goal_id": user_id, "arrow_code": self.arrow.get_arrow_codes_from_waypoint_id( user_status["schedules"][0]["goal"]["waypoint_id"])[0], "waypoint_id": user_status["schedules"][0]["goal"]["waypoint_id"], }] routes = self.route.get_shortest_routes(start_point, goal_points, reverse=False) if len(routes) == 0: print("cant carry_route") return carry_route = min(routes.items(), key=lambda x: x[1]["cost"])[1] current_time = time() vehicle_schedule = deepcopy( self.topicVehicleSubscribe.get_template()["schedules"][0]) vehicle_schedule.update({ "name": "pickup", "start_time": current_time, "duration": 1000, "action": Vehicle.ACTION.MOVE, "route": { "start": { "waypoint_id": pick_up_route["goal_waypoint_id"], }, "goal": { "waypoint_id": pick_up_route["start_waypoint_id"], }, "arrow_codes": pick_up_route["arrow_codes"], } }) self.vehicles[vehicle_id]["schedules"].append(vehicle_schedule) vehicle_schedule = deepcopy( self.topicVehicleSubscribe.get_template()["schedules"][0]) vehicle_schedule.update({ "name": "takeOn", "start_time": current_time + 1000, "duration": 10, "action": Vehicle.ACTION.STOP, }) self.vehicles[vehicle_id]["schedules"].append(vehicle_schedule) vehicle_schedule = deepcopy( self.topicVehicleSubscribe.get_template()["schedules"][0]) vehicle_schedule.update({ "name": "carry", "start_time": current_time + 1010, "duration": 1000, "action": Vehicle.ACTION.MOVE, "route": { "start": { "waypoint_id": carry_route["start_waypoint_id"], }, "goal": { "waypoint_id": carry_route["goal_waypoint_id"], }, "arrow_codes": carry_route["arrow_codes"], } }) self.vehicles[vehicle_id]["schedules"].append(vehicle_schedule) vehicle_schedule = deepcopy( self.topicVehicleSubscribe.get_template()["schedules"][0]) vehicle_schedule.update({ "name": "discharge", "start_time": current_time + 2010, "duration": 10, "action": Vehicle.ACTION.STOP, }) self.vehicles[vehicle_id]["schedules"].append(vehicle_schedule) vehicle_schedule = deepcopy( self.topicVehicleSubscribe.get_template()["schedules"][0]) vehicle_schedule.update({ "name": "standBy", "start_time": current_time + 2020, "duration": 86400, "action": SimTaxi.ACTION.STANDBY, }) self.vehicles[vehicle_id]["schedules"].append(vehicle_schedule) payload = self.topicVehicleSubscribe.serialize( {"schedules": self.vehicles[vehicle_id]["schedules"]}) self.publish( self.topicVehicleSubscribe.root + "/" + vehicle_id + "/schedules", payload) self.relations[user_id] = vehicle_id self.relations[vehicle_id] = user_id self.publish_relations() def publish_relations(self): message = self.topicFleetManagerPublish.get_template() message["time"] = time() message["relations"] = self.relations payload = self.topicFleetManagerPublish.serialize(message) self.publish(self.topicFleetManagerPublish.private, payload)