class SchedulerExample(Agent): '''This agent can be used to demonstrate scheduling and acutation of devices. It reserves a non-existant device, then acts when its time comes up. Since there is no device, this will cause an error. ''' def __init__(self, **kwargs): super(SchedulerExample, self).__init__(**kwargs) @Core.receiver('onsetup') def setup(self, sender, **kwargs): self._agent_id = config['agentid'] @Core.receiver('onstart') def startup(self, sender, **kwargs): # self.publish_schedule() self.use_rpc() @PubSub.subscribe('pubsub', topics.ACTUATOR_SCHEDULE_ANNOUNCE(campus='campus', building='building',unit='unit')) def actuate(self, peer, sender, bus, topic, headers, message): print ("response:",topic,headers,message) if headers[headers_mod.REQUESTER_ID] != agent_id: return '''Match the announce for our fake device with our ID Then take an action. Note, this command will fail since there is no actual device''' headers = { 'requesterID': agent_id, } self.vip.pubsub.publish( 'pubsub', topics.ACTUATOR_SET(campus='campus', building='building',unit='unit', point='point'), headers, str(0.0)) def publish_schedule(self): '''Periodically publish a schedule request''' headers = { 'AgentID': agent_id, 'type': 'NEW_SCHEDULE', 'requesterID': agent_id, #The name of the requesting agent. 'taskID': agent_id + "-ExampleTask", #The desired task ID for this task. It must be unique among all other scheduled tasks. 'priority': 'LOW', #The desired task priority, must be 'HIGH', 'LOW', or 'LOW_PREEMPT' } start = str(datetime.datetime.now()) end = str(datetime.datetime.now() + datetime.timedelta(minutes=1)) msg = [ ['campus/building/unit',start,end] #Could add more devices # ["campus/building/device1", #First time slot. # "2014-1-31 12:27:00", #Start of time slot. # "2016-1-31 12:29:00"], #End of time slot. # ["campus/building/device2", #Second time slot. # "2014-1-31 12:26:00", #Start of time slot. # "2016-1-31 12:30:00"], #End of time slot. # ["campus/building/device3", #Third time slot. # "2014-1-31 12:30:00", #Start of time slot. # "2016-1-31 12:32:00"], #End of time slot. #etc... ] self.vip.pubsub.publish( 'pubsub', topics.ACTUATOR_SCHEDULE_REQUEST, headers, msg) def use_rpc(self): try: start = str(datetime.datetime.now()) end = str(datetime.datetime.now() + datetime.timedelta(minutes=1)) msg = [ ['campus/building/unit3',start,end] ] result = self.vip.rpc.call( 'platform.actuator', 'request_new_schedule', agent_id, "some task", 'LOW', msg).get(timeout=10) print("schedule result", result) except Exception as e: print ("Could not contact actuator. Is it running?") print(e) return try: if result['result'] == 'SUCCESS': result = self.vip.rpc.call( 'platform.actuator', 'set_point', agent_id, 'campus/building/unit3/some_point', '0.0').get(timeout=10) print("Set result", result) except Exception as e: print ("Expected to fail since there is no real device to set") print(e)
class Agent(PublishMixin, BaseAgent): def __init__(self, **kwargs): super(Agent, self).__init__(**kwargs) self.lock_timer = None self.lock_acquired = False self.tasklet = None self.data_queue = green.WaitQueue(self.timer) self.value_queue = green.WaitQueue(self.timer) self.weather_data_queue = green.WaitQueue(self.timer) self.last_run_time = None self.is_running = False self.remaining_time = None self.task_id = agent_id self.retry_schedule = None self.start = None self.end = None def setup(self): super(Agent, self).setup() self.scheduled_task() def startrun(self, algo=None): _log.debug('start diagnostic') if algo is None: algo = afdd.AFDD(self, config_path).run_all self.tasklet = greenlet.greenlet(algo) self.is_running = True self.last_run_time = datetime.datetime.now() self.tasklet.switch() def scheduled_task(self): ''' Schedule re-occuring diagnostics ''' _log.debug('Schedule Dx') headers = { 'type': 'NEW_SCHEDULE', 'requesterID': agent_id, 'taskID': agent_id, 'priority': 'LOW_PREEMPT' } min_run_hour = math.floor(min_run_window / 3600) min_run_minute = int((min_run_window / 3600 - min_run_hour) * 60) self.start = datetime.datetime.now().replace(hour=start_hour, minute=start_minute) self.end = self.start + datetime.timedelta(hours=2, minutes=30) run_start = self.end - datetime.datetime.now() required_diagnostic_time = datetime.timedelta( hours=min_run_hour, minutes=min_run_minute) if run_start < required_diagnostic_time: self.start = self.start + datetime.timedelta(days=1) self.end = self.start + datetime.timedelta(hours=2, minutes=30) sched_time = datetime.datetime.now() + datetime.timedelta( days=day_run_interval + 1) sched_time = sched_time.replace(hour=0, minute=1) else: sched_time = datetime.datetime.now() + datetime.timedelta( days=day_run_interval) self.start = str(self.start) self.end = str(self.end) self.task_timer = self.periodic_timer( 60, self.publish_json, topics.ACTUATOR_SCHEDULE_REQUEST(), headers, [[ "{campus}/{building}/{unit}".format(**rtu_path), self.start, self.end ]]) event = sched.Event(self.scheduled_task) self.next = self.schedule(sched_time, event) @matching.match_headers({ headers_mod.REQUESTER_ID: agent_id, 'type': 'CANCEL_SCHEDULE' }) @matching.match_exact(topics.ACTUATOR_SCHEDULE_RESULT()) def preempt(self): if self.is_running: self.cancel_greenlet() @matching.match_headers({headers_mod.REQUESTER_ID: agent_id}) @matching.match_exact(topics.ACTUATOR_SCHEDULE_ANNOUNCE(**rtu_path)) def on_schedule(self, topic, headers, message, match): msg = jsonapi.loads(message[0]) now = datetime.datetime.now() self.remaining_time = headers.get('window', 0) if self.task_id == headers.get('taskID', ''): if self.remaining_time < termination_window: if self.is_running: self.cancel_greenlet() elif (self.remaining_time > min_run_window and (self.last_run_time is None or (now - self.last_run_time) > datetime.timedelta(hours=23, minutes=50))): self.startrun() @matching.match_headers({headers_mod.REQUESTER_ID: agent_id}) @matching.match_exact(topics.ACTUATOR_SCHEDULE_RESULT()) def schedule_result(self, topic, headers, message, match): msg = jsonapi.loads(message[0]) _log.debug('Actuator response received') self.task_timer.cancel() @matching.match_exact(topics.DEVICES_VALUE(point='all', **rtu_path)) def on_new_data(self, topic, headers, message, match): data = jsonapi.loads(message[0]) #Check override status if int(data["VoltronPBStatus"]) == 1: if self.is_running: _log.debug("User override is initiated...") headers = { 'Content-Type': 'text/plain', 'requesterID': agent_id, } self.publish( topics.ACTUATOR_SET(point="VoltronFlag", **rtu_path), headers, str(0.0)) self.cancel_greenlet() else: self.data_queue.notify_all(data) @matching.match_headers({headers_mod.REQUESTER_ID: agent_id}) @matching.match_glob(topics.ACTUATOR_VALUE(point='*', **rtu_path)) def on_set_result(self, topic, headers, message, match): self.value_queue.notify_all((match.group(1), True)) @matching.match_headers({headers_mod.REQUESTER_ID: agent_id}) @matching.match_glob(topics.ACTUATOR_ERROR(point='*', **rtu_path)) def on_set_error(self, topic, headers, message, match): self.value_queue.notify_all((match.group(1), False)) def cancel_greenlet(self): #kill all tasks currently in the queue self.data_queue.kill_all() self.value_queue.kill_all() #kill current tasklet self.tasklet.throw() self.is_running = False def sleep(self, timeout): _log.debug('wait for steady state({})'.format(timeout)) green.sleep(timeout, self.timer) def get_new_data(self, timeout=None): _log.debug('get_new_data({})'.format(timeout)) return self.data_queue.wait(timeout) def command_equip(self, point_name, value, timeout=None): _log.debug('set_point({}, {}, {})'.format(point_name, value, timeout)) headers = { 'Content-Type': 'text/plain', 'requesterID': agent_id, } self.publish(topics.ACTUATOR_SET(point=point_name, **rtu_path), headers, str(value)) try: return self.value_queue.wait(timeout) except green.Timeout: return True def weather_request(self, timeout=None): _log.debug('weather request for {}'.format(zip_code)) headers = {'Content-Type': 'text/plain', 'requesterID': agent_id} msg = {'zipcode': str(zip_code)} self.publish_json('weather/request', headers, msg) try: return self.weather_data_queue.wait(timeout) except green.Timeout: return 'INCONCLUSIVE' matching.match_headers({headers_mod.REQUESTER_ID: agent_id}) @matching.match_exact('weather/response/temperature/temp_f') def weather_response(self, topic, headers, message, match): data = float(jsonapi.loads(message[0])) print data self.weather_data_queue.notify_all(data)
class Agent(PublishMixin, BaseAgent): '''This agent can be used to demonstrate scheduling and acutation of devices. It reserves a non-existant device, then acts when its time comes up. Since there is no device, this will cause an error. ''' def __init__(self, **kwargs): super(Agent, self).__init__(**kwargs) def setup(self): # Demonstrate accessing a value from the config file _log.info(config['message']) # Always call the base class setup() super(Agent, self).setup() self.publish_schedule() @matching.match_exact( topics.ACTUATOR_SCHEDULE_ANNOUNCE(campus='campus', building='building', unit='unit')) @matching.match_headers({headers_mod.REQUESTER_ID: agent_id}) def actuate(self, topic, headers, message, match): '''Match the announce for our fake device with our ID Then take an action. Note, this command will fail since there is no actual device''' headers = { 'requesterID': agent_id, } self.publish_json( topics.ACTUATOR_SET(campus='campus', building='building', unit='unit', point='point'), headers, str(0.0)) @periodic(settings.SCHEDULE_PERIOD) def publish_schedule(self): '''Periodically publish a schedule request''' headers = { 'AgentID': agent_id, 'type': 'NEW_SCHEDULE', 'requesterID': agent_id, #The name of the requesting agent. 'taskID': agent_id + "-ExampleTask", #The desired task ID for this task. It must be unique among all other scheduled tasks. 'priority': 'LOW', #The desired task priority, must be 'HIGH', 'LOW', or 'LOW_PREEMPT' } start = str(datetime.datetime.now()) end = str(datetime.datetime.now() + datetime.timedelta(minutes=1)) msg = [ ['campus/building/unit', start, end] #Could add more devices # ["campus/building/device1", #First time slot. # "2014-1-31 12:27:00", #Start of time slot. # "2016-1-31 12:29:00"], #End of time slot. # ["campus/building/device2", #Second time slot. # "2014-1-31 12:26:00", #Start of time slot. # "2016-1-31 12:30:00"], #End of time slot. # ["campus/building/device3", #Third time slot. # "2014-1-31 12:30:00", #Start of time slot. # "2016-1-31 12:32:00"], #End of time slot. #etc... ] self.publish_json(topics.ACTUATOR_SCHEDULE_REQUEST, headers, msg)