class Agent(PublishMixin, BaseAgent): def setup(self): super(Agent, self).setup() self.damper = 0 @matching.match_regex(topics.ACTUATOR_LOCK_ACQUIRE() + '(/.*)') def on_lock_result(self, topic, headers, message, match): _log.debug( "Topic: {topic}, {headers}, Message: {message}".format( topic=topic, headers=headers, message=message)) self.publish(topics.ACTUATOR_LOCK_RESULT() + match.group(0), headers, jsonapi.dumps('SUCCESS')) @matching.match_regex(topics.ACTUATOR_SET() + '(/.*/([^/]+))') def on_new_data(self, topic, headers, message, match): _log.debug( "Topic: {topic}, {headers}, Message: {message}".format( topic=topic, headers=headers, message=message)) if match.group(2) == 'Damper': self.damper = int(message[0]) self.publish(topics.ACTUATOR_VALUE() + match.group(0), headers, message[0]) @periodic(5) def send_data(self): data = { 'ReturnAirTemperature': 55, 'OutsideAirTemperature': 50, 'MixedAirTemperature': 45, 'Damper': self.damper } self.publish_ex(topics.DEVICES_VALUE(point='all', **rtu_path), {}, ('application/json', jsonapi.dumps(data)))
def pre_cool_get_lock(self, e_start,e_end): now = datetime.datetime.now() day=now.weekday() if not Schedule[day]: print"Unoccupied today" return self.state = 'PRECOOL' #e_end = e_start.replace(hour=cpp_end_hour, minute =0, second = 0) #e_end = e_start + datetime.timedelta(minutes=2) e_start_unix = time.mktime(e_start.timetuple()) e_end_unix = time.mktime(e_end.timetuple()) def run_schedule_builder(): #current_time = time.mktime(current_time.timetuple()) self.schedule_builder(e_start_unix, e_end_unix, current_spacetemp=77.0, pre_csp=csp_pre, building_thermal_constant=building_thermal_constant, normal_coolingstpt=76.0, timestep_length=timestep_length, dr_csp=csp_cpp) self.lock_handler=None self.lock_handler = run_schedule_builder headers = { headers_mod.CONTENT_TYPE: headers_mod.CONTENT_TYPE.JSON, 'requesterID': agent_id} self.publish(topics.ACTUATOR_LOCK_ACQUIRE(**rtu_path), headers)
def setup(self): super(Agent, self).setup() headers = { 'Content-Type': 'text/plain', 'requesterID': agent_id, } self.publish(topics.ACTUATOR_LOCK_ACQUIRE(**rtu_path), headers)
def setup(self): """acquire lock fom actuator agent""" super(Agent, self).setup() headers = { 'Content-Type': 'text/plain', 'requesterID': agent_id, } self.lock_timer = self.periodic_timer( 1, self.publish, topics.ACTUATOR_LOCK_ACQUIRE(**rtu_path), headers)
def update_schedule_state(self, unix_time): headers = { 'Content-Type': 'text/plain', 'requesterID': agent_id, } now = datetime.datetime.fromtimestamp(unix_time) day = now.weekday() if Schedule[day]: self.schedule_state = True #TODO: set this up to handle platform not running. #This will hang after a while otherwise. self.lock_timer = super(Agent, self).periodic_timer( 1, self.publish, topics.ACTUATOR_LOCK_ACQUIRE(**rtu_path), headers) else: self.schedule_state = False self.publish(topics.ACTUATOR_LOCK_RELEASE(**rtu_path), headers)
class Agent(PublishMixin, BaseAgent): """Class agent""" 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) def setup(self): """acquire lock fom actuator agent""" super(Agent, self).setup() headers = { 'Content-Type': 'text/plain', 'requesterID': agent_id, } self.lock_timer = self.periodic_timer( 1, self.publish, topics.ACTUATOR_LOCK_ACQUIRE(**rtu_path), headers) @matching.match_exact(topics.ACTUATOR_LOCK_ACQUIRE(**rtu_path)) def __on_lock_sent(self, topic, headers, message, match): """lock recieved""" self.lock_timer.cancel() @matching.match_exact(topics.ACTUATOR_LOCK_RESULT(**rtu_path)) def __on_lock_result(self, topic, headers, message, match): """lock result""" msg = jsonapi.loads(message[0]) holding_lock = self.lock_acquired if headers['requesterID'] == agent_id: self.lock_acquired = msg == 'SUCCESS' elif msg == 'SUCCESS': self.lock_acquired = False if self.lock_acquired and not holding_lock: self.start() @matching.match_exact(topics.DEVICES_VALUE(point='all', **rtu_path)) def __on_new_data(self, topic, headers, message, match): """watching for new data""" data = jsonapi.loads(message[0]) self.data_queue.notify_all(data) @matching.match_glob(topics.ACTUATOR_VALUE(point='*', **rtu_path)) def __on_set_result(self, topic, headers, message, match): """set value in conroller""" self.value_queue.notify_all((match.group(1), True)) @matching.match_glob(topics.ACTUATOR_ERROR(point='*', **rtu_path)) def __on_set_error(self, topic, headers, message, match): """watch for actuator error""" self.value_queue.notify_all((match.group(1), False)) def __sleep(self, timeout=None): """built in sleep in green""" #_log.debug('sleep({})'.format(timeout)) green.sleep(timeout, self.timer) def __get_new_data(self, timeout=None): """wait for new data""" _log.debug('get_new_data({})'.format(timeout)) return self.data_queue.wait(timeout) def __command_equip(self, point_name, value, timeout=None): """set value in controller""" _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 None def __time_out(self): """if timeout occurs""" global fan1_norm global fan2_norm global csp_norm global min_damper if fan1_norm == 0: self.__sleep( 600) #If controller loses volttron heartbeat will reset self.start() #wait at least this long else: try: self.__command_equip('CoolSupplyFanSpeed1', fan1_norm) except green.Timeout: self.__sleep(600) self.start() try: self.__command_equip('CoolSupplyFanSpeed2', fan2_norm) except green.Timeout: self.__sleep(600) self.start() try: self.__command_equip('ESMDamperMinPosition', min_damper) except green.Timeout: self.__sleep(600) self.start() try: self.__command_equip('ReturnAirCO2Stpt', csp_norm) except green.Timeout: self.__sleep(600) self.start() @matching.match_exact( topics.DEVICES_VALUE(point='Occupied', **rtu_path)) def __overide(self, topic, headers, message, match): """watch for override from controller""" data = jsonapi.loads(message[0]) if not bool(data): self.tasklet = greenlet.greenlet(self.__on_override) self.tasklet.switch() def __on_override(self): global fan1_norm global fan2_norm global csp_norm global min_damper global override_flag if fan1_norm != 0 and not override_flag: override_flag = True _log.debug('Override initiated') try: self.__command_equip('CoolSupplyFanSpeed1', fan1_norm) except green.Timeout: self.__sleep( 43200) #if override wait for 12 hours then resume self.start( ) #catalyst will default to original operations with no volttron heatbeat try: self.__command_equip('CoolSupplyFanSpeed2', fan2_norm) except green.Timeout: self.__sleep(43200) self.start() try: self.__command_equip('ESMDamperMinPosition', min_damper) except green.Timeout: self.__sleep(43200) self.start() try: self.__command_equip('ReturnAirCO2Stpt', csp_norm) except green.Timeout: self.__sleep(43200) self.start() elif fan1_norm == 0 and not override_flag: override_flag = True self.__sleep(43200) self.start() def start(self): """Starting point for DR application""" global override override_flag = False self.tasklet = greenlet.greenlet(self.__go) self.tasklet.switch() def __go(self): """start main DR procedure""" #self.__command_equip('CoolSupplyFanSpeed1', 75) #self.__command_equip('CoolSupplyFanSpeed2', 90) #self.__command_equip('ESMDamperMinPosition', 5) global fan1_norm global fan2_norm global csp_norm global min_damper try: self.__command_equip('ReturnAirCO2Stpt', 74) except green.Timeout: self.__time_out() try: voltron_data = self.__get_new_data() except green.Timeout: self.__time_out() # Gracefully handle exception min_damper = float(voltron_data["ESMDamperMinPosition"]) fan1_norm = float(voltron_data["CoolSupplyFanSpeed1"]) fan2_norm = float(voltron_data["CoolSupplyFanSpeed2"]) csp_norm = float(voltron_data["ReturnAirCO2Stpt"]) _log.debug("Zone normal cooling temperature setpoint: " + repr(csp_norm)) _log.debug("Supply fan cooling speed 1: " + repr(fan1_norm)) _log.debug("Supply fan cooling speed 2: " + repr(fan2_norm)) _log.debug("Normal minimum damper position: " + repr(min_damper)) self.tasklet = greenlet.greenlet(self.get_signal) self.tasklet.switch() def __pre_cpp_timer(self): """Schedule to run in get_signal""" _log.debug("Pre-cooling for CPP Event" ) #pre-cool change cooling set point self.tasklet = greenlet.greenlet(self.__pre_csp) self.tasklet.switch() self.pre_timer = self.periodic_timer(settings.pre_cooling_time, self.__pre_cpp_cooling) def __pre_cpp_cooling(self): """start pre cooling procedure""" self.tasklet = greenlet.greenlet(self.__pre_csp) self.tasklet.switch() def __pre_csp(self): """set cooling temp. set point""" self.__sleep(1) try: voltron_data = self.__get_new_data() except green.Timeout: self.__time_out() csp_now = float(voltron_data["ReturnAirCO2Stpt"]) if csp_now > settings.csp_pre: try: csp = csp_now - cooling_slope self.__command_equip("ReturnAirCO2Stpt", csp) except green.Timeout: self.__time_out() elif csp_now <= settings.csp_pre: try: self.__command_equip("ReturnAirCO2Stpt", settings.csp_pre) except green.Timeout: self.__time_out() self.pre_timer.cancel() def __accelerated_pre_cpp_timer(self): """if DR signal is received after normal pre""" _log.debug("Pre-cooling for CPP Event" ) #pre-cool change cooling set point self.tasklet = greenlet.greenlet(self.__accelerated_pre_csp) self.tasklet.switch() self.pre_timer = self.periodic_timer( settings.pre_time, self.__accelerated_cpp_cooling) def __accelerated_cpp_cooling(self): """start accelerated pre-cooling""" self.tasklet = greenlet.greenlet(self.__accelerated_pre_csp) self.tasklet.switch() def __accelerated_pre_csp(self): """set cooling temp set point""" _log.debug("Accelerated pre-cooling for CPP Event") global accel_slope self.__sleep(2) try: voltron_data = self.__get_new_data() except green.Timeout: self.__time_out() csp_now = float(voltron_data["ReturnAirCO2Stpt"]) csp = csp_now - accel_slope if csp_now > settings.csp_pre: try: self.__command_equip("ReturnAirCO2Stpt", csp) except green.Timeout: self.__time_out() elif csp_now <= settings.csp_pre: try: self.__command_equip("ReturnAirCO2Stpt", settings.csp_pre) except green.Timeout: self.__time_out() self.pre_timer.cancel() def __during_cpp_timer(self): """during CPP scheduled in get_signal""" self.tasklet = greenlet.greenlet(self.__during_cpp) self.tasklet.switch() def __during_cpp(self): """start CPP procedure""" _log.debug("During CPP Event") # remove when done testing self.__sleep(2) global fan1_norm global fan2_norm cpp_damper = settings.cpp_damper fan_reduction = settings.fan_reduction cpp_csp = settings.cpp_csp cpp_fan1 = fan1_norm - fan1_norm * fan_reduction cpp_fan2 = fan2_norm - fan2_norm * fan_reduction self.__sleep(1) try: self.__command_equip("CoolSupplyFanSpeed1", cpp_fan1) except green.Timeout: self.__time_out() try: self.__command_equip("CoolSupplyFanSpeed2", cpp_fan2) except green.Timeout: self.__time_out() try: self.__command_equip("ReturnAirCO2Stpt", cpp_csp) except green.Timeout: self.__time_out() try: self.__command_equip('ESMDamperMinPosition', cpp_damper) except green.Timeout: self.__time_out() def __after_cpp_timer(self): """after CPP scheduled in get_signal""" self.tasklet = greenlet.greenlet(self.__restore_fan_damper) self.tasklet.switch() _log.debug("After CPP Event, returning to normal operations") self.tasklet = greenlet.greenlet(self.__restore_cooling_setpoint) self.tasklet.switch() timer = settings.after_time self.after_timer = self.periodic_timer(timer, self.__after_cpp_cooling) def __after_cpp_cooling(self): """Start after CPP procedure""" _log.debug("After_CPP_COOLING") self.tasklet = greenlet.greenlet(self.__restore_cooling_setpoint) self.tasklet.switch() def __restore_fan_damper(self): """restore original fan speeds""" global fan1_norm global fan2_norm global min_damper self.__sleep( 2 ) # so screen _log.debugs in correct order remove after testing. try: self.__command_equip("ESMDamperMinPosition", min_damper) except green.Timeout: self.__time_out() try: self.__command_equip("CoolSupplyFanSpeed1", fan1_norm) except green.Timeout: self.__time_out() try: self.__command_equip("CoolSupplyFanSpeed2", fan2_norm) except green.Timeout: self.__time_out() def __restore_cooling_setpoint(self): """restore normal cooling temp setpoint""" global csp_norm self.__sleep(2) #remove after testing try: voltron_data = self.__get_new_data() except green.Timeout: self.__time_out() csp_now = float(voltron_data["ReturnAirCO2Stpt"]) if csp_now > csp_norm: csp = csp_now - cooling_slope try: self.__command_equip("ReturnAirCO2Stpt", csp) except green.Timeout: self.__time_out() elif csp_now <= csp_norm: self.after_timer.cancel() try: self.__command_equip("ReturnAirCO2Stpt", csp_norm) except green.Timeout: self.__time_out() def get_signal(self): """get and format DR signal and schedule DR proc.""" #Pull signal from source self.__sleep(2) #remove after testing global csp_norm global cooling_slope global accel_slope time_now = time.mktime(datetime.datetime.now().timetuple()) time_pre = time.mktime( datetime.datetime.now().replace(hour=settings.pre_cpp_hour, minute=23, second=0, microsecond=0).timetuple()) time_event = time.mktime(datetime.datetime.now().replace( hour=settings.during_cpp_hour, minute=25, second=0, microsecond=0).timetuple()) time_after = time.mktime(datetime.datetime.now().replace( hour=settings.after_cpp_hour, minute=27, second=0, microsecond=0).timetuple()) if (settings.signal and time_now < time_pre): _log.debug("Scheduling1") time_step = settings.pre_cooling_time / 3600 #cooling_slope = (csp_norm-settings.csp_pre)/((((time_event-time_pre)/3600)-0.5)*time_step) cooling_slope = 1 # for testing use a constant temp = ((time_event - time_pre) / 3600) _log.debug("cooling slope: " + repr(cooling_slope)) pre_cpp_time = datetime.datetime.now().replace( hour=settings.pre_cpp_hour, minute=23, second=0, microsecond=0) self.schedule(pre_cpp_time, sched.Event(self.__pre_cpp_timer)) during_cpp_time = datetime.datetime.now().replace( hour=settings.during_cpp_hour, minute=25, second=0, microsecond=0) self.schedule(during_cpp_time, sched.Event(self.__during_cpp_timer)) after_cpp_time = datetime.datetime.now().replace( hour=settings.after_cpp_hour, minute=27, second=0, microsecond=0) self.schedule(after_cpp_time, sched.Event(self.__after_cpp_timer)) #self.start_timer.cancel() elif (settings.signal and time_now > time_pre and time_now < time_event): _log.debug("Scheduling2") #self.start_timer.cancel() #accel_slope = (csp_norm-settings.csp_pre)/((time_event-time_now)/(3600)) accel_slope = 2 #for testing use a constant during_cpp_time = datetime.datetime.now().replace( hour=settings.during_cpp_hour, minute=36, second=20, microsecond=0) self.schedule(during_cpp_time, sched.Event(self.__during_cpp_timer)) after_cpp_time = datetime.datetime.now().replace( hour=settings.after_cpp_hour, minute=39, second=10, microsecond=0) self.schedule(after_cpp_time, sched.Event(self.__after_cpp_timer)) self.__accelerated_pre_cpp_timer() elif (settings.signal and time_now > time_event and time_now < time_after): _log.debug("Too late to pre-cool!") #self.start_timer.cancel() after_cpp_time = datetime.datetime.now().replace( hour=settings.after_cpp_hour, minute=17, second=0, microsecond=0) self.schedule(after_cpp_time, sched.Event(self.__after_cpp_timer)) self.tasklet = greenlet.greenlet(self.__during_cpp) self.tasklet.switch() else: _log.debug("CPP Event Is Over") #self.start_timer.cancel() self.__sleep(60) self.get_signal()
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) def setup(self): super(Agent, self).setup() headers = { 'Content-Type': 'text/plain', 'requesterID': agent_id, } self.lock_timer = self.periodic_timer( 1, self.publish, topics.ACTUATOR_LOCK_ACQUIRE(**rtu_path), headers) def start(self, algo=None): if algo is None: algo = afdd self.tasklet = greenlet.greenlet(algo) self.tasklet.switch(self) @matching.match_exact(topics.ACTUATOR_LOCK_ACQUIRE(**rtu_path)) def on_lock_sent(self, topic, headers, message, match): self.lock_timer.cancel() @matching.match_exact(topics.ACTUATOR_LOCK_RESULT(**rtu_path)) def on_lock_result(self, topic, headers, message, match): msg = jsonapi.loads(message[0]) holding_lock = self.lock_acquired if headers['requesterID'] == agent_id: self.lock_acquired = msg == 'SUCCESS' elif msg == 'SUCCESS': self.lock_acquired = False if self.lock_acquired and not holding_lock: self.start() @matching.match_exact(topics.DEVICES_VALUE(point='all', **rtu_path)) def on_new_data(self, topic, headers, message, match): data = jsonapi.loads(message[0]) self.data_queue.notify_all(data) @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_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 sleep(self, timeout): _log.debug('sleep({})'.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 set_point(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 None
class Agent(PublishMixin, BaseAgent): """Class agent""" def __init__(self, **kwargs): super(Agent, self).__init__(**kwargs) self.schedule_state = False self.fan1_norm = 0 self.fan2_norm = 0 self.csp_norm = 0 self.accel_slope = 0 self.cooling_slope = 0 self.min_damper = 0 self.override_flag = False self.lock_timer = None self.lock_acquired = False self.timers = [] self.tasks = [] self.tasklet = None self.data_queue = green.WaitQueue(self.timer) self.value_queue = green.WaitQueue(self.timer) self.running = False def setup(self): """acquire lock fom actuator agent""" super(Agent, self).setup() @matching.match_exact( topics.DEVICES_VALUE(point='CoolCall1', **rtu_path)) def dr_signal(self, topic, headers, message, match): data = jsonapi.loads(message[0]) if not self.running and bool(data): print("start") self.running = True time_now = time.mktime(datetime.datetime.now().timetuple()) self.update_schedule_state(time_now) #self.schedule(next_time, self.update_schedule_state) if (self.schedule_state): self.start() else: _log.debug( "DR signal is False or day is not an occupied day") def update_schedule_state(self, unix_time): headers = { 'Content-Type': 'text/plain', 'requesterID': agent_id, } now = datetime.datetime.fromtimestamp(unix_time) day = now.weekday() if Schedule[day]: self.schedule_state = True #TODO: set this up to handle platform not running. #This will hang after a while otherwise. self.lock_timer = super(Agent, self).periodic_timer( 1, self.publish, topics.ACTUATOR_LOCK_ACQUIRE(**rtu_path), headers) else: self.schedule_state = False self.publish(topics.ACTUATOR_LOCK_RELEASE(**rtu_path), headers) @matching.match_exact(topics.ACTUATOR_LOCK_ACQUIRE(**rtu_path)) def _on_lock_sent(self, topic, headers, message, match): """lock request received""" self.lock_timer.cancel() @matching.match_exact(topics.ACTUATOR_LOCK_RESULT(**rtu_path)) def _on_lock_result(self, topic, headers, message, match): """lock result""" msg = jsonapi.loads(message[0]) holding_lock = self.lock_acquired if headers['requesterID'] == agent_id: self.lock_acquired = msg == 'SUCCESS' elif msg == 'SUCCESS': self.lock_acquired = False if self.lock_acquired and not holding_lock: self.start() @matching.match_exact(topics.DEVICES_VALUE(point='all', **rtu_path)) def _on_new_data(self, topic, headers, message, match): """watching for new data""" data = jsonapi.loads(message[0]) self.data_queue.notify_all(data) @matching.match_glob(topics.ACTUATOR_VALUE(point='*', **rtu_path)) def _on_set_result(self, topic, headers, message, match): """set value in conroller""" self.value_queue.notify_all((match.group(1), True)) @matching.match_glob(topics.ACTUATOR_ERROR(point='*', **rtu_path)) def _on_set_error(self, topic, headers, message, match): """watch for actuator error""" self.value_queue.notify_all((match.group(1), False)) def _sleep(self, timeout=None): """built in sleep in green""" _log.debug('sleep({})'.format(timeout)) green.sleep(timeout, self.timer) def _get_new_data(self, timeout=data_timeout): #timeout=data_timeout """wait for new data""" _log.debug('get_new_data({})'.format(timeout)) return self.data_queue.wait(timeout) def _command_equip(self, point_name, value, timeout): """set value in controller""" _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)) while True: point, success = self.value_queue.wait(timeout) if point == point_name: if success: return raise CommandSetError() def _time_out(self): """if timeout occurs""" if (self.fan1_norm and self.fan2_norm and self.min_damper and self.csp_norm): try: self._command_equip('CoolSupplyFanSpeed1', self.fan1_norm) self._command_equip('CoolSupplyFanSpeed2', self.fan2_norm) self._command_equip('ESMDamperMinPosition', self.min_damper) self._command_equip('StandardDamperMinPosition', self.csp_norm) except green.Timeout: pass for timer in self.timers: timer.cancel() del self.timers[:] current = greenlet.getcurrent() for task in self.tasks: if task is not current: task.parent = current task.throw() print 'adding current task to task list' self.tasks[:] = [current] self._sleep( 600) #If controller loses volttron heartbeat will reset self.running = False @matching.match_exact( topics.DEVICES_VALUE(point='Occupied', **rtu_path) ) # for now look for Occuppied, DR Override will be added def _override(self, topic, headers, message, match): """watch for override from controller""" data = jsonapi.loads(message[0]) if not bool(data): self.greenlet(self._on_override) def _on_override(self): if not self.override_flag: self.override_flag = True _log.debug("Override initiated") for timer in self.timers: timer.cancel() del self.timers[:] current = greenlet.getcurrent() for task in self.tasks: if task is not current: task.parent = current task.throw() if self.fan1_norm: try: self._command_equip('CoolSupplyFanSpeed1', self.fan1_norm) self._command_equip('CoolSupplyFanSpeed2', self.fan2_norm) self._command_equip('ESMDamperMinPosition', self.min_damper) self._command_equip('ReturnAirCO2Stpt', self.csp_norm) except green.Timeout: self._sleep( 43200) #if override wait for 12 hours then resume self._go( ) #catalyst will default to original operations with no volttron heatbeat self._sleep(43200) self.override_flag = False self.running = False elif not self.fan1_norm and not self.override_flag: self.override_flag = True self._sleep(43200) self.override_flag = False self.running = False def start(self): """Starting point for DR application""" self.override_flag = False self.greenlet(self._go) def _go(self): """start main DR procedure""" self._command_equip('StandardDamperChangeOverSetPoint', 75, 20) self._command_equip('CoolSupplyFanSpeed2', 90, 20) self._command_equip('CoolSupplyFanSpeed1', 75, 20) self._command_equip('StandardDamperMinPosition', 65, 20) try: self._command_equip('ESMDamperMinPosition', 5, 20) voltron_data = self._get_new_data() except CommandSetError: self._time_out() except green.Timeout: self._time_out() self.min_damper = float(voltron_data["ESMDamperMinPosition"]) self.fan1_norm = float(voltron_data["CoolSupplyFanSpeed1"]) self.fan2_norm = float(voltron_data["CoolSupplyFanSpeed2"]) self.csp_norm = float(voltron_data["ReturnAirCO2Stpt"]) _log.debug("Zone normal cooling temperature setpoint: " + repr(self.csp_norm)) _log.debug("Supply fan cooling speed 1: " + repr(self.fan1_norm)) _log.debug("Supply fan cooling speed 2: " + repr(self.fan2_norm)) _log.debug("Normal minimum damper position: " + repr(self.min_damper)) self.get_signal() def _pre_cpp_timer(self): """Schedule to run in get_signal""" _log.debug("Pre-cooling for CPP Event" ) #pre-cool change cooling set point self._pre_csp() self.pre_timer = self.periodic_timer(settings.pre_time, self._pre_cpp_cooling) def _pre_cpp_cooling(self): """start pre cooling procedure""" self.greenlet(self._pre_csp) def _pre_csp(self): """set cooling temp set point""" try: voltron_data = self._get_new_data() except green.Timeout: self._time_out() csp_now = float(voltron_data["ReturnAirCO2Stpt"]) if csp_now > csp_pre and not csp < csp_pre: try: csp = csp_now - self.cooling_slope self._command_equip("ReturnAirCO2Stpt", csp) except green.Timeout: self._time_out() elif csp_now <= csp_pre and not csp < csp_pre: try: self._command_equip("ReturnAirCO2Stpt", settings.csp_pre) except green.Timeout: self._time_out() self.pre_timer.cancel() def _accelerated_pre_cpp_timer(self): """if DR signal is received after normal pre""" _log.debug("Pre-cooling for CPP Event" ) #pre-cool change cooling set point self._accelerated_pre_csp() self.pre_timer = self.periodic_timer(settings.pre_time, self._accelerated_cpp_cooling) def _accelerated_cpp_cooling(self): """start accelerated pre-cooling""" self.greenlet(self._accelerated_pre_csp) def _accelerated_pre_csp(self): """set cooling temp set point""" _log.debug("Accelerated pre-cooling for CPP Event") try: voltron_data = self._get_new_data() except green.Timeout: self._time_out() csp_now = float(voltron_data["ReturnAirCO2Stpt"]) csp = csp_now - self.accel_slope if csp_now > csp_pre and not csp < csp_pre: try: self._command_equip("ReturnAirCO2Stpt", csp) except green.Timeout: self._time_out() elif csp_now <= csp_pre or csp < csp_pre: try: self._command_equip("ReturnAirCO2Stpt", settings.csp_pre) except green.Timeout: self._time_out() self.pre_timer.cancel() def _during_cpp_timer(self): """during CPP scheduled in get_signal""" self.greenlet(self._during_cpp) def _during_cpp(self): """start CPP procedure""" # remove when done testing _log.debug("During CPP Event") damper_cpp = settings.damper_cpp fan_reduction = settings.fan_reduction csp_cpp = settings.csp_cpp cpp_fan1 = self.fan1_norm - self.fan1_norm * fan_reduction cpp_fan2 = self.fan2_norm - self.fan2_norm * fan_reduction try: self._command_equip("CoolSupplyFanSpeed1", cpp_fan1) self._command_equip("CoolSupplyFanSpeed2", cpp_fan2) self._command_equip("ReturnAirCO2Stpt", csp_cpp) self._command_equip('ESMDamperMinPosition', damper_cpp) except green.Timeout: self._time_out() def _after_cpp_timer(self): """after CPP scheduled in get_signal""" self.greenlet(self._restore_fan_damper) _log.debug("After CPP Event, returning to normal operations") self.greenlet(self._restore_cooling_setpoint) timer = settings.after_time self.after_timer = self.periodic_timer(timer, self._after_cpp_cooling) def _after_cpp_cooling(self): """Start after CPP procedure""" _log.debug("After_CPP_COOLING") self.greenlet(self._restore_cooling_setpoint) def _restore_fan_damper(self): """restore original fan speeds""" try: self._command_equip("ESMDamperMinPosition", self.min_damper) self._command_equip("CoolSupplyFanSpeed1", self.fan1_norm) self._command_equip("CoolSupplyFanSpeed2", self.fan2_norm) except green.Timeout: self._time_out() def _restore_cooling_setpoint(self): """restore normal cooling temp setpoint""" try: voltron_data = self._get_new_data() except green.Timeout: self._time_out() csp_now = float(voltron_data["ReturnAirCO2Stpt"]) if csp_now > self.csp_norm: csp = csp_now - self.cooling_slope try: self._command_equip("ReturnAirCO2Stpt", csp) except green.Timeout: self._time_out() elif csp_now <= self.csp_norm: self.after_timer.cancel() try: self._command_equip("ReturnAirCO2Stpt", self.csp_norm) self._sleep(60) self.running = False except green.Timeout: self._time_out() def periodic_timer(self, *args, **kwargs): timer = super(Agent, self).periodic_timer(*args, **kwargs) self.timers.append(timer) return timer def schedule(self, time, event): super(Agent, self).schedule(time, event) self.timers.append(event) def greenlet(self, *args, **kwargs): task = greenlet.greenlet(*args, **kwargs) self.tasks.append(task) current = greenlet.getcurrent() if current.parent is not None: task.parent = current.parent task.switch() def get_signal(self): """get and format DR signal and schedule DR proc.""" time_now = time.mktime(datetime.datetime.now().timetuple()) time_pre = time.mktime( datetime.datetime.now().replace(hour=settings.pre_cpp_hour, minute=0, second=0, microsecond=0).timetuple()) time_event = time.mktime(datetime.datetime.now().replace( hour=settings.during_cpp_hour, minute=12, second=0, microsecond=0).timetuple()) time_after = time.mktime(datetime.datetime.now().replace( hour=settings.after_cpp_hour, minute=14, second=0, microsecond=0).timetuple()) if (settings.signal and time_now < time_pre): _log.debug("Scheduling1") time_step = settings.pre_time / 3600 #self.cooling_slope = (self.csp_norm - settings.csp_pre) / ((((time_event - time_pre) / 3600) - 0.5) * time_step) self.cooling_slope = 1 # for testing use a constant temp = ((time_event - time_pre) / 3600) _log.debug("cooling slope: " + repr(self.cooling_slope)) self.schedule(time_pre, sched.Event(self._pre_cpp_timer)) self.schedule(time_event, sched.Event(self._during_cpp_timer)) after_cpp_time = datetime.datetime.now().replace( hour=settings.after_cpp_hour, minute=59, second=0, microsecond=0) self.schedule(time_after, sched.Event(self._after_cpp_timer)) #self.start_timer.cancel() elif (settings.signal and time_now > time_pre and time_now < time_event): _log.debug("Scheduling2") #self.start_timer.cancel() #self.accel_slope = (self.csp_norm - settings.csp_pre) / ((time_event - time_now) / (3600)) self.accel_slope = 2 #for testing use a constant #self.cooling_slope = (self.csp_norm - settings.csp_pre) / ((((time_event - time_pre) / 3600) - 0.5) * time_step) self.cooling_slope = 1 # for testing use a constant self.schedule(time_event, sched.Event(self._during_cpp_timer)) self.schedule(time_after, sched.Event(self._after_cpp_timer)) self._accelerated_pre_cpp_timer() elif (settings.signal and time_now > time_event and time_now < time_after): _log.debug("Too late to pre-cool!") #self.start_timer.cancel() self.schedule(time_after, sched.Event(self._after_cpp_timer)) self._during_cpp() else: _log.debug("CPP Event Is Over") #self.start_timer.cancel() self._sleep(60) self.get_signal()