def from_dict(request_dict): id = request_dict.get('id', generate_uuid()) request = TaskRequest(id=id) request.load_type = request_dict["loadType"] request.load_id = request_dict["loadId"] request.user_id = request_dict["userId"] request.earliest_pickup_time = TimeStamp.from_str( request_dict["earliestPickupTime"]) request.latest_pickup_time = TimeStamp.from_str( request_dict["latestPickupTime"]) pickup_area_dict = request_dict.get('pickup_pose', None) if pickup_area_dict: request.pickup_pose = Area.from_dict(pickup_area_dict) else: # when the provided dict is from json schema request.pickup_pose = Area() request.pickup_pose.name = request_dict.get("pickupLocation", '') request.pickup_pose.floor_number = request_dict.get( "pickupLocationLevel", 0) delivery_area_dict = request_dict.get('delivery_pose', None) if delivery_area_dict: request.delivery_pose = Area.from_dict(delivery_area_dict) else: # when the provided dict is from json schema request.delivery_pose = Area() request.delivery_pose.name = request_dict.get( "deliveryLocation", '') request.delivery_pose.floor_number = request_dict.get( "deliveryLocationLevel", 0) request.priority = request_dict["priority"] return request
def check_msg_retries(self, message, zyre_msg_type, **kwargs): msg_type = message['header']['type'] if msg_type not in self.message_types: return msg_id = message['header']['msgId'] queued_msg = self.unacknowledged_msgs.get(msg_id, None) if queued_msg: retry = queued_msg.get('retry_number', 0) self.unacknowledged_msgs[msg_id]['retry_number'] = retry + 1 self.unacknowledged_msgs[msg_id][ 'last_retry'] = self.unacknowledged_msgs[msg_id]['next_retry'] else: self.unacknowledged_msgs[msg_id] = dict() self.unacknowledged_msgs[msg_id]['retry_number'] = 0 current_ts = ts.get_time_stamp() self.unacknowledged_msgs[msg_id]['first_attempt'] = current_ts self.unacknowledged_msgs[msg_id]['last_retry'] = current_ts self.unacknowledged_msgs[msg_id]['zyre_msg_type'] = zyre_msg_type if 'receiverIds' in message['header'].keys(): self.unacknowledged_msgs[msg_id]['receiverIds'] = message[ 'header']['receiverIds'] else: self.unacknowledged_msgs[msg_id]['receiverIds'] = list() self.unacknowledged_msgs[msg_id]['msg_args'] = dict() self.unacknowledged_msgs[msg_id]['msg_args']['msg'] = message self.unacknowledged_msgs[msg_id]['msg_args'].update(kwargs) deadline = timedelta(seconds=5**5) self.unacknowledged_msgs[msg_id]['reply_by'] = ts.get_time_stamp( deadline) # TODO This needs to be probably adapted by message type next_attempt = timedelta(seconds=5) self.unacknowledged_msgs[msg_id]['next_retry'] = ts.get_time_stamp( next_attempt)
def init_ztp(self): midnight = self.get_current_time().replace(hour=0, minute=0, second=0, microsecond=0) ztp = TimeStamp() ztp.timestamp = midnight return ztp
def is_executable(self): current_time = TimeStamp() start_time = TimeStamp.from_datetime(self.start_time) if start_time < current_time: return True else: return False
def reference_to_current_time(earliest_time, latest_time): delta = timedelta(minutes=earliest_time) r_earliest_time = TimeStamp(delta).to_str() delta = timedelta(minutes=latest_time) r_latest_time = TimeStamp(delta).to_str() return r_earliest_time, r_latest_time
def to_timestamp(ztp, r_time): """ Returns a timestamp ztp(TimeStamp) + relative time(float) in seconds """ if r_time == float('inf'): time_ = TimeStamp() time_.timestamp = datetime.max else: time_ = ztp + timedelta(seconds=r_time) return time_
def __init__(self, id=''): if not id: self.id = generate_uuid() else: self.id = id self.pickup_pose = Area() self.delivery_pose = Area() self.earliest_pickup_time = TimeStamp() self.latest_pickup_time = TimeStamp() self.user_id = '' self.load_type = '' self.load_id = '' self.priority = -1
def from_dict(sub_area_reservation_dict): sub_area_reservation = SubAreaReservation() sub_area_reservation.sub_area_id = sub_area_reservation_dict[ 'subAreaId'] sub_area_reservation.task_id = sub_area_reservation_dict['taskId'] sub_area_reservation.robot_id = sub_area_reservation_dict['robotId'] sub_area_reservation.start_time = TimeStamp.from_str( sub_area_reservation_dict['startTime']) sub_area_reservation.end_time = TimeStamp.from_str( sub_area_reservation_dict['endTime']) sub_area_reservation.status = sub_area_reservation_dict['status'] sub_area_reservation.required_capacity = sub_area_reservation_dict[ 'requiredCapacity'] return sub_area_reservation
def update_timestamp(message): header = message.get('header') if header: header.update(timeStamp=TimeStamp().to_str()) else: header = MessageFactoryBase.get_header(None) message.update(header)
def __init__(self, ccu_store, api, stp_solver, allocation_method, round_time=5, **kwargs): self.logger = logging.getLogger("mrs.auctioneer") self.robot_ids = list() self.timetables = dict() self.api = api self.stp = STP(stp_solver) self.allocation_method = allocation_method self.round_time = timedelta(seconds=round_time) self.alternative_timeslots = kwargs.get('alternative_timeslots', False) self.logger.debug("Auctioneer started") self.tasks_to_allocate = dict() self.allocations = list() self.waiting_for_user_confirmation = list() self.round = Round() # TODO: Update zero_timepoint today_midnight = datetime.today().replace(hour=0, minute=0, second=0, microsecond=0) self.zero_timepoint = TimeStamp() self.zero_timepoint.timestamp = today_midnight
def task_status_cb(self, msg): payload = msg['payload'] timestamp = TimeStamp.from_str( msg["header"]["timestamp"]).to_datetime() task_status = TaskStatus.from_payload(payload) if self.robot_id == task_status.robot_id: task = Task.get_task(task_status.task_id) self.logger.debug("Received task status %s for task %s", task_status.task_status, task.task_id) self.logger.debug("Sending task status %s for task %s", task_status.task_status, task.task_id) self.api.publish(msg, groups=["TASK-ALLOCATION"]) if task_status.task_status == TaskStatusConst.ONGOING: self.update_timetable(task, task_status.task_progress, timestamp) elif task_status.task_status == TaskStatusConst.COMPLETED: self.logger.debug("Completing execution of task %s", task.task_id) self.task = None task.update_status(task_status.task_status)
def relative_to_ztp(ztp, time_, resolution="seconds"): """Returns the relative time between the given time_ (datetime) and the ztp (TimeStamp)""" if time_.isoformat().startswith("9999-12-31T"): r_time = float('inf') else: r_time = TimeStamp.from_datetime(time_).get_difference(ztp, resolution) return r_time
def from_dict(timetable_dict, stp): robot_id = timetable_dict['robot_id'] timetable = Timetable(robot_id, stp) stn_cls = timetable.initialize_stn() zero_timepoint = timetable_dict.get('zero_timepoint') if zero_timepoint: timetable.zero_timepoint = TimeStamp.from_str(zero_timepoint) else: timetable.zero_timepoint = zero_timepoint timetable.risk_metric = timetable_dict['risk_metric'] timetable.temporal_metric = timetable_dict['temporal_metric'] stn = timetable_dict.get('stn') if stn: timetable.stn = stn_cls.from_dict(stn) else: timetable.stn = stn dispatchable_graph = timetable_dict.get('dispatchable_graph') if dispatchable_graph: timetable.dispatchable_graph = stn_cls.from_dict(dispatchable_graph) else: timetable.dispatchable_graph = dispatchable_graph schedule = timetable_dict.get('schedule') if schedule: timetable.schedule = stn_cls.from_dict(schedule) else: timetable.schedule = schedule return timetable
def _get_value(cls, key, value): if key in ['task_id', 'round_id', 'action_id']: return from_str(value) elif key in ['ztp', 'earliest_admissible_time', 'earliest_start_time']: return TimeStamp.from_str(value) else: return value
def announce_tasks(self): tasks = list(self.tasks_to_allocate.values()) earliest_task = Task.get_earliest_task(tasks) closure_time = earliest_task.pickup_constraint.earliest_time - self.closure_window if not self.is_valid_time(closure_time) and self.alternative_timeslots: # Closure window should be long enough to allow robots to bid (tune if necessary) closure_time = self.get_current_time() + self.closure_window elif not self.is_valid_time( closure_time) and not self.alternative_timeslots: self.logger.warning( "Task %s cannot not be allocated at its given temporal constraints", earliest_task.task_id) earliest_task.update_status(TaskStatusConst.PREEMPTED) self.tasks_to_allocate.pop(earliest_task.task_id) return self.changed_timetable.clear() for task in tasks: if not task.hard_constraints: self.update_soft_constraints(task) self.round = Round(self.robot_ids, self.tasks_to_allocate, n_tasks=len(tasks), closure_time=closure_time, alternative_timeslots=self.alternative_timeslots, simulator=self.simulator) earliest_admissible_time = TimeStamp() earliest_admissible_time.timestamp = self.get_current_time( ) + timedelta(minutes=1) task_announcement = TaskAnnouncement(tasks, self.round.id, self.timetable_manager.ztp, earliest_admissible_time) self.logger.debug("Starting round: %s", self.round.id) self.logger.debug("Number of tasks to allocate: %s", len(tasks)) msg = self.api.create_message(task_announcement) self.logger.debug("Auctioneer announces tasks %s", [task.task_id for task in tasks]) self.round.start() self.api.publish(msg, groups=['TASK-ALLOCATION'])
def time_to_close(self): current_time = TimeStamp() if current_time < self.closure_time: return False self.logger.debug("Closing round at %s", current_time) self.opened = False return True
def get_header(message_type, meta_model='msg', recipients=[]): if recipients is not None and not isinstance(recipients, list): raise Exception("Recipients must be a list of strings") return {"header": {'type': message_type, 'metamodel': 'ropod-%s-schema.json' % meta_model, 'msgId': generate_uuid(), 'timestamp': TimeStamp().to_str(), 'receiverIds': recipients}}
def is_executable(self): """Returns True if the given task needs to be dispatched based on the task schedule; returns False otherwise """ current_time = TimeStamp() if self.start_time < current_time: return True else: return False
def add_next_retry(self, msg_id): retry = self.unacknowledged_msgs[msg_id]['retry_number'] timeout = 5**retry next_attempt = timedelta(seconds=timeout) self.unacknowledged_msgs[msg_id][ 'last_retry'] = self.unacknowledged_msgs[msg_id]['next_retry'] self.unacknowledged_msgs[msg_id]['next_retry'] = ts.get_time_stamp( next_attempt) self.unacknowledged_msgs[msg_id]['retry_number'] = retry + 1
def __init__(self, robot_id, api, robot_store, stp_solver, task_type): self.id = robot_id self.api = api self.stp = STP(stp_solver) self.timetable = Timetable(robot_id, self.stp) today_midnight = datetime.today().replace(hour=0, minute=0, second=0, microsecond=0) self.timetable.zero_timepoint = TimeStamp() self.timetable.zero_timepoint.timestamp = today_midnight
def trigger(self): print("Test triggered") test_msg = dict() test_msg['header'] = dict() test_msg['payload'] = dict() test_msg['header']['type'] = 'START-TEST' test_msg['header']['metamodel'] = 'ropod-msg-schema.json' test_msg['header']['msgId'] = generate_uuid() test_msg['header']['timestamp'] = TimeStamp().to_str() test_msg['payload']['metamodel'] = 'ropod-bid_round-schema.json' self.shout(test_msg)
def __new__(cls, message_type, meta_model=None, **kwargs): recipients = kwargs.get('recipients', list()) if recipients is not None and not isinstance(recipients, list): raise Exception("Recipients must be a list of strings") return { 'type': message_type, 'metamodel': meta_model, 'msgId': str(generate_uuid()), 'timestamp': TimeStamp().to_str(), 'receiverIds': recipients }
def from_dict(timetable_dict): robot_id = timetable_dict['robot_id'] stp_solver = STP(timetable_dict['solver_name']) timetable = Timetable(robot_id, stp_solver) stn_cls = timetable.stp_solver.get_stn() ztp = timetable_dict.get('ztp') timetable.ztp = TimeStamp.from_str(ztp) timetable.stn = stn_cls.from_dict(timetable_dict['stn']) timetable.dispatchable_graph = stn_cls.from_dict(timetable_dict['dispatchable_graph']) timetable.stn_tasks = timetable_dict['stn_tasks'] return timetable
def start(self): """ Starts and auction round: - opens the round - marks the round as not finished opened: The auctioneer processes bid msgs closed: The auctioneer no longer processes incoming bid msgs, i.e., bid msgs received after the round has closed are not considered in the election process After the round closes, the election process takes place finished: The election process is over, i.e., an mrs has been made (or an exception has been raised) """ open_time = TimeStamp() self.closure_time = TimeStamp(delta=self.round_time) self.logger.debug("Round opened at %s and will close at %s", open_time, self.closure_time) self.finished = False self.opened = True
def to_stn_task(self, task_lot): """ Converts a task to an stn task Args: task_lot (obj): task_lot object to be converted zero_timepoint (TimeStamp): Zero Time Point. Origin time to which task temporal information is referenced to """ start_timepoint_constraints = task_lot.constraints.timepoint_constraints[0] r_earliest_start_time, r_latest_start_time = TimepointConstraints.relative_to_ztp(start_timepoint_constraints, self.zero_timepoint) delta = timedelta(minutes=1) earliest_navigation_start = TimeStamp(delta) r_earliest_navigation_start = earliest_navigation_start.get_difference(self.zero_timepoint, "minutes") stn_task = STNTask(task_lot.task.task_id, r_earliest_navigation_start, r_earliest_start_time, r_latest_start_time, task_lot.start_location, task_lot.finish_location) return stn_task
def fetch(self): try: self.logger.debug("Fetching timetable of robot %s", self.robot_id) timetable_mongo = TimetableMongo.objects.get_timetable(self.robot_id) self.stn = self.stn.from_dict(timetable_mongo.stn) self.dispatchable_graph = self.stn.from_dict(timetable_mongo.dispatchable_graph) self.ztp = TimeStamp.from_datetime(timetable_mongo.ztp) self.stn_tasks = {task_id: STNTask.from_dict(task) for (task_id, task) in timetable_mongo.stn_tasks.items()} except DoesNotExist: self.logger.debug("The timetable of robot %s is empty", self.robot_id) # Resetting values self.stn = self.stp_solver.get_stn() self.dispatchable_graph = self.stp_solver.get_stn()
def task_status_cb(self, msg): payload = msg['payload'] timestamp = TimeStamp.from_str( msg["header"]["timestamp"]).to_datetime() task_status = TaskStatus.from_payload(payload) if self.robot_id == task_status.robot_id: task = Task.get_task(task_status.task_id) self.logger.debug("Received task status %s for task %s", task_status.task_status, task.task_id) if task_status.task_status == TaskStatusConst.ONGOING: self._update_timetable(task, task_status.task_progress, timestamp) task.update_status(task_status.task_status)
def from_payload(payload): round_id = from_str(payload['roundId']) zero_timepoint = TimeStamp.from_str(payload['zeroTimepoint']) tasks_dict = payload['tasksLots'] tasks_lots = list() for task_id, task_dict in tasks_dict.items(): Task.create_new(task_id=task_id) tasks_lots.append(TaskLot.from_payload(task_dict)) task_announcement = TaskAnnouncement(tasks_lots, round_id, zero_timepoint) return task_announcement
def task_status_cb(self, msg): while self.deleting_task: time.sleep(0.1) self.processing_task = True payload = msg['payload'] timestamp = TimeStamp.from_str( msg["header"]["timestamp"]).to_datetime() task_status = TaskStatus.from_payload(payload) task_progress = task_status.task_progress task = Task.get_task(task_status.task_id) self.logger.debug("Received task status %s for task %s by %s", task_status.task_status, task_status.task_id, task_status.robot_id) if task_status.task_status == TaskStatusConst.ONGOING: self._update_progress(task, task_progress, timestamp) self.update_timetable(task, task_status.robot_id, task_progress, timestamp) self._update_task_schedule(task, task_progress, timestamp) task.update_status(task_status.task_status) elif task_status.task_status == TaskStatusConst.COMPLETED: self.logger.debug("Adding task %s to tasks to remove", task.task_id) self.tasks_to_remove.append((task, task_status.task_status)) elif task_status.task_status == TaskStatusConst.UNALLOCATED: self.re_allocate(task) elif task_status.task_status == TaskStatusConst.PREEMPTED: if task.status.status == TaskStatusConst.PREEMPTED: self.logger.warning("Task %s is already preempted", task_status.task_id) return try: self._remove_task(task, task_status.task_status) except TaskNotFound: return self.processing_task = False
def get_task_schedule(self, task_id, robot_id): # For now, returning the start navigation time from the dispatchable graph task_schedule = dict() timetable = self.timetables.get(robot_id) relative_start_navigation_time = timetable.dispatchable_graph.get_time( task_id, "navigation") relative_start_time = timetable.dispatchable_graph.get_time( task_id, "start") relative_latest_finish_time = timetable.dispatchable_graph.get_time( task_id, "finish", False) self.logger.debug("Current time %s: ", TimeStamp()) self.logger.debug("zero_timepoint %s: ", self.zero_timepoint) self.logger.debug("Relative start navigation time: %s", relative_start_navigation_time) self.logger.debug("Relative start time: %s", relative_start_time) self.logger.debug("Relative latest finish time: %s", relative_latest_finish_time) start_navigation_time = self.zero_timepoint + timedelta( minutes=relative_start_navigation_time) start_time = self.zero_timepoint + timedelta( minutes=relative_start_time) finish_time = self.zero_timepoint + timedelta( minutes=relative_latest_finish_time) self.logger.debug("Start navigation of task %s: %s", task_id, start_navigation_time) self.logger.debug("Start of task %s: %s", task_id, start_time) self.logger.debug("Latest finish of task %s: %s", task_id, finish_time) task_schedule['start_time'] = start_navigation_time.to_datetime() task_schedule['finish_time'] = finish_time.to_datetime() return task_schedule