Example #1
0
 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'))
Example #2
0
    class Agent(PublishMixin, BaseAgent):
        def __init__(self, **kwargs):
            super(Agent, self).__init__(**kwargs)
            self.lock_acquired = False
            self.thread = None
            self.data_queue = multithreading.WaitQueue()
            self.value_queue = multithreading.WaitQueue()

        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 start(self, algo=None):
            if algo is None:
                algo = afdd

            def run():
                sock = messaging.Socket(zmq.PUSH)
                sock.connect(publish_address)
                with contextlib.closing(sock):
                    algo(self, sock)

            self.thread = threading.Thread(target=run)
            self.thread.daemon = True
            self.thread.start()

        @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 get_new_data(self, timeout=None):
            _log.debug('get_new_data({})'.format(timeout))
            return self.data_queue.wait(timeout)

        def set_point(self, sock, point_name, value, timeout=None):
            _log.debug('set_point({}, {}, {})'.format(point_name, value,
                                                      timeout))
            headers = {
                'Content-Type': 'text/plain',
                'requesterID': agent_id,
            }
            with self.value_queue.condition:
                sock.send_message(topics.ACTUATOR_SET(point=point_name,
                                                      **rtu_path),
                                  headers,
                                  str(value),
                                  flags=zmq.NOBLOCK)
                try:
                    return self.value_queue._wait(timeout)
                except multithreading.Timeout:
                    return None
Example #3
0
    class Agent(PublishMixin, BaseAgent):
        """Class agent"""
        def __init__(self, **kwargs):
            super(Agent, self).__init__(**kwargs)
            self.default_firststage_fanspeed = 0.0
            self.default_secondstage_fanspeed = 0.0
            self.default_damperstpt = 0.0
            self.default_coolingstpt = 0.0
            self.default_heatingstpt = 65.0

            self.current_spacetemp = 72.0

            self.state = 'STARTUP'
            self.e_start_msg = None
            self.lock_handler = None
            self.error_handler = None
            self.actuator_handler = None

            self.all_scheduled_events = {}
            self.currently_running_dr_event_handlers = []
            self.headers = {
                headers_mod.CONTENT_TYPE: headers_mod.CONTENT_TYPE.JSON,
                'requesterID': agent_id
            }

        @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])
            if headers['requesterID'] == agent_id:
                if msg == 'SUCCESS' and self.lock_handler is not None:
                    self.lock_handler()
                if msg == 'FAILURE' and self.error_handler is not None:
                    self.error_handler(msg)

        @matching.match_glob(topics.ACTUATOR_ERROR(point='*', **rtu_path))
        def _on_error_result(self, topic, headers, message, match):
            """lock result"""
            if headers.get('requesterID', '') == agent_id:
                if self.error_handler is not None:
                    self.error_handler(match, jsonapi.loads(message[0]))

        @matching.match_glob(topics.ACTUATOR_VALUE(point='*', **rtu_path))
        def _on_actuator_result(self, topic, headers, message, match):
            """lock result"""
            msg = jsonapi.loads(message[0])
            print 'Actuator Results:', match, msg
            if headers['requesterID'] == agent_id:
                if self.actuator_handler is not None:
                    self.actuator_handler(match, jsonapi.loads(message[0]))

        @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.current_spacetemp = float(data["ZoneTemp"])
            self.current_spacetemp = 76
            droveride = bool(int(data["CoolCall2"]))
            occupied = bool(int(data["Occupied"]))

            if droveride and self.state not in ('IDLE', 'CLEANUP', 'STARTUP'):
                print 'User Override Initiated'
                self.cancel_event()

            if not occupied and self.state in ('DR_EVENT', 'RESTORE'):
                self.cancel_event()

            if self.state == 'IDLE' or self.state == 'STARTUP':
                #self.default_coolingstpt = float(data["CoolingStPt"])
                #self.default_heatingstpt = float(data["HeatingStPt"])
                self.default_coolingstpt = 75.0
                self.default_heatingstpt = 65.0
                self.default_firststage_fanspeed = float(
                    data["CoolSupplyFanSpeed1"])
                self.default_secondstage_fanspeed = float(
                    data["CoolSupplyFanSpeed2"])
                self.default_damperstpt = float(data["ESMDamperMinPosition"])

            if self.state == 'STARTUP':
                self.state = 'IDLE'

        @matching.match_exact(topics.OPENADR_EVENT())
        def _on_dr_event(self, topic, headers, message, match):
            if self.state == 'STARTUP':
                print "DR event ignored because of startup."
                return
            """handle openADR events"""
            msg = jsonapi.loads(message[0])
            print('EVENT Received')
            print(msg)
            e_id = msg['id']
            e_status = msg['status']
            e_start = msg['start']
            e_start = datetime.datetime.strptime(e_start, datefmt)
            today = datetime.datetime.now().date()
            #e_start_day = e_start.date()
            #e_end = e_start.replace(hour=cpp_end_hour, minute =0, second = 0)
            current_datetime = datetime.datetime.now()
            e_end = e_start + datetime.timedelta(minutes=2)

            if current_datetime > e_end:
                print 'Too Late Event is Over'
                return

            if e_status == 'cancelled':
                if e_start in self.all_scheduled_events:
                    print 'Event Cancelled'
                    self.all_scheduled_events[e_start].cancel()
                    del self.all_scheduled_events[e_start]

                if e_start.date() == today and (self.state == 'PRECOOL'
                                                or self.state == 'DR_EVENT'):
                    self.cancel_event()
                return

            #TODO: change this to UTC later
            #utc_now = datetime.datetime.utcnow()

            if today > e_start.date():
                if e_start in self.all_scheduled_events:
                    self.all_scheduled_events[e_start].cancel()
                    del self.all_scheduled_events[e_start]

                return

            for item in self.all_scheduled_events.keys():
                if e_start.date() == item.date():
                    if e_start.time() != item.time():
                        print "Updating Event"
                        self.all_scheduled_events[item].cancel()
                        del self.all_scheduled_events[item]
                        if e_start.date() == today and (self.state == 'PRECOOL'
                                                        or self.state
                                                        == 'DR_EVENT'):
                            self.update_running_event()
                            self.state = 'IDLE'
                        break
                    elif e_start.time() == item.time():
                        print "same event"
                        return
            #if e_id in self.all_scheduled_dr_events and update is None:


#                 if e_id == self.currently_running_msg:
#                 return
#return

#Minutes used for testing
#event_start = e_start - datetime.timedelta(hours = max_precool_hours)
            event_start = e_start - datetime.timedelta(
                minutes=max_precool_hours)

            event = sched.Event(self.pre_cool_get_lock, args=[e_start, e_end])
            self.schedule(event_start, event)
            self.all_scheduled_events[e_start] = event

        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 modify_temp_set_point(self, csp, hsp):
            self.publish(
                topics.ACTUATOR_SET(point='StandardDamperChangeOverSetPoint',
                                    **rtu_path), self.headers, str(csp))
            self.publish(
                topics.ACTUATOR_SET(point='StandardDamperMinPosition',
                                    **rtu_path), self.headers, str(hsp))

            def backup_run():
                self.modify_temp_set_point(csp, hsp)
                self.lock_handler = None

            self.lock_handler = backup_run

        def start_dr_event(self):
            self.state = 'DR_EVENT'
            self.publish(
                topics.ACTUATOR_SET(point='StandardDamperChangeOverSetPoint',
                                    **rtu_path), self.headers, str(csp_cpp))

            new_fan_speed = self.default_firststage_fanspeed - (
                self.default_firststage_fanspeed * fan_reduction)
            new_fan_speed = max(new_fan_speed, 0)
            self.publish(
                topics.ACTUATOR_SET(point='CoolSupplyFanSpeed1', **rtu_path),
                self.headers, str(new_fan_speed))

            new_fan_speed = self.default_secondstage_fanspeed - (
                self.default_firststage_fanspeed * fan_reduction)
            new_fan_speed = max(new_fan_speed, 0)
            self.publish(
                topics.ACTUATOR_SET(point='CoolSupplyFanSpeed2', **rtu_path),
                self.headers, str(new_fan_speed))

            self.publish(
                topics.ACTUATOR_SET(point='ESMDamperMinPosition', **rtu_path),
                self.headers, str(damper_cpp))

            def backup_run():
                self.start_dr_event()
                self.lock_handler = None

            self.lock_handler = backup_run

        def start_restore_event(self, csp, hsp):
            self.state = 'RESTORE'
            print 'Restore:  Begin restoring normal operations'
            self.publish(
                topics.ACTUATOR_SET(point='StandardDamperChangeOverSetPoint',
                                    **rtu_path), self.headers, str(csp))
            self.publish(
                topics.ACTUATOR_SET(point='StandardDamperMinPosition',
                                    **rtu_path), self.headers,
                str(hsp))  #heating
            self.publish(
                topics.ACTUATOR_SET(point='CoolSupplyFanSpeed1', **rtu_path),
                self.headers, str(self.default_firststage_fanspeed))
            self.publish(
                topics.ACTUATOR_SET(point='CoolSupplyFanSpeed2', **rtu_path),
                self.headers, str(self.default_secondstage_fanspeed))

            self.publish(
                topics.ACTUATOR_SET(point='ESMDamperMinPosition', **rtu_path),
                self.headers, str(self.default_damperstpt))

            def backup_run():
                self.start_restore_event(csp, hsp)
                self.lock_handler = None

            self.lock_handler = backup_run

        def update_running_event(self):
            self.publish(
                topics.ACTUATOR_SET(point='StandardDamperChangeOverSetPoint',
                                    **rtu_path), self.headers,
                str(self.default_coolingstpt))
            self.publish(
                topics.ACTUATOR_SET(point='StandardDamperMinPosition',
                                    **rtu_path), self.headers,
                str(self.default_heatingstpt))
            self.publish(
                topics.ACTUATOR_SET(point='CoolSupplyFanSpeed1', **rtu_path),
                self.headers, str(self.default_firststage_fanspeed))
            self.publish(
                topics.ACTUATOR_SET(point='CoolSupplyFanSpeed2', **rtu_path),
                self.headers, str(self.default_secondstage_fanspeed))

            self.publish(
                topics.ACTUATOR_SET(point='ESMDamperMinPosition', **rtu_path),
                self.headers, str(self.default_damperstpt))

            for event in self.currently_running_dr_event_handlers:
                event.cancel()
            self.currently_running_dr_event_handlers = []

        def cancel_event(self):
            self.state = 'CLEANUP'
            self.publish(
                topics.ACTUATOR_SET(point='StandardDamperChangeOverSetPoint',
                                    **rtu_path), self.headers,
                str(self.default_coolingstpt))
            self.publish(
                topics.ACTUATOR_SET(point='StandardDamperMinPosition',
                                    **rtu_path), self.headers,
                str(self.default_heatingstpt))
            self.publish(
                topics.ACTUATOR_SET(point='CoolSupplyFanSpeed1', **rtu_path),
                self.headers, str(self.default_firststage_fanspeed))
            self.publish(
                topics.ACTUATOR_SET(point='CoolSupplyFanSpeed2', **rtu_path),
                self.headers, str(self.default_secondstage_fanspeed))

            self.publish(
                topics.ACTUATOR_SET(point='ESMDamperMinPosition', **rtu_path),
                self.headers, str(self.default_damperstpt))

            for event in self.currently_running_dr_event_handlers:
                event.cancel()

            self.currently_running_dr_event_handlers = []

            def backup_run():
                self.cancel_event()
                self.lock_handler = None

            self.lock_handler = backup_run

            expected_values = {
                'StandardDamperChangeOverSetPoint': self.default_coolingstpt,
                'StandardDamperMinPosition': self.default_heatingstpt,
                'CoolSupplyFanSpeed1': self.default_firststage_fanspeed,
                'CoolSupplyFanSpeed2': self.default_secondstage_fanspeed,
                'ESMDamperMinPosition': self.default_damperstpt
            }

            EPSILON = 0.5  #allowed difference from expected value

            def result_handler(point, value):
                #print "actuator point being handled:", point, value
                expected_value = expected_values.pop(point, None)
                if expected_value is not None:
                    diff = abs(expected_value - value)
                    if diff > EPSILON:
                        _log.debug("Did not get back expected value for",
                                   point)

                if not expected_values:
                    self.actuator_handler = None
                    self.lock_handler = None
                    self.state = 'IDLE'

                    headers = {
                        headers_mod.CONTENT_TYPE:
                        headers_mod.CONTENT_TYPE.JSON,
                        'requesterID': agent_id
                    }
                    self.publish(topics.ACTUATOR_LOCK_RELEASE(**rtu_path),
                                 headers)

            self.actuator_handler = result_handler

        def schedule_builder(self, start_time, end_time, current_spacetemp,
                             pre_csp, building_thermal_constant,
                             normal_coolingstpt, timestep_length, dr_csp):
            """schedule all events for a DR event."""

            print 'Scheduling all DR actions'
            pre_hsp = pre_csp - 5.0
            current_time = time.time()
            ideal_cooling_window = int(
                ((current_spacetemp - pre_csp) / building_thermal_constant) *
                3600)
            ideal_precool_start_time = start_time - ideal_cooling_window

            max_cooling_window = start_time - current_time

            cooling_window = ideal_cooling_window if ideal_cooling_window < max_cooling_window else max_cooling_window

            precool_start_time = start_time - cooling_window

            if (max_cooling_window > 0):
                print "Schedule Pre Cooling"
                num_cooling_timesteps = int(
                    math.ceil(float(cooling_window) / float(timestep_length)))
                cooling_step_delta = (normal_coolingstpt -
                                      pre_csp) / num_cooling_timesteps

                for step_index in range(1, num_cooling_timesteps + 1):
                    event_time = start_time - (step_index * timestep_length)
                    csp = pre_csp + ((step_index - 1) * cooling_step_delta)

                    print 'Precool step:', datetime.datetime.fromtimestamp(
                        event_time), csp
                    event = sched.Event(self.modify_temp_set_point,
                                        args=[csp, pre_hsp])
                    self.schedule(event_time, event)
                    self.currently_running_dr_event_handlers.append(event)

            else:
                print "Too late to pre-cool!"

            restore_window = int(
                ((dr_csp - normal_coolingstpt) / building_thermal_constant) *
                3600)
            restore_start_time = end_time
            num_restore_timesteps = int(
                math.ceil(float(restore_window) / float(timestep_length)))
            restore_step_delta = (dr_csp -
                                  normal_coolingstpt) / num_restore_timesteps

            print 'Schedule DR Event:', datetime.datetime.fromtimestamp(
                start_time), dr_csp
            event = sched.Event(self.start_dr_event)
            self.schedule(start_time, event)
            self.currently_running_dr_event_handlers.append(event)

            print 'Schedule Restore Event:', datetime.datetime.fromtimestamp(
                end_time), dr_csp - restore_step_delta
            event = sched.Event(
                self.start_restore_event,
                args=[dr_csp - restore_step_delta, self.default_heatingstpt])
            self.schedule(end_time, event)
            self.currently_running_dr_event_handlers.append(event)

            for step_index in range(1, num_restore_timesteps):
                event_time = end_time + (step_index * timestep_length)
                csp = dr_csp - ((step_index + 1) * restore_step_delta)

                print 'Restore step:', datetime.datetime.fromtimestamp(
                    event_time), csp
                event = sched.Event(self.modify_temp_set_point,
                                    args=[csp, self.default_heatingstpt])
                self.schedule(event_time, event)
                self.currently_running_dr_event_handlers.append(event)

            event_time = end_time + (num_restore_timesteps * timestep_length)
            print 'Schedule Cleanup Event:', datetime.datetime.fromtimestamp(
                event_time)
            event = sched.Event(self.cancel_event)
            self.schedule(event_time, event)
            self.currently_running_dr_event_handlers.append(event)
Example #4
0
    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()
Example #5
0
    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
Example #6
0
    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()