def loop(self): # Pause loop to modify trigger. # Prevents execution of trigger while variables are # being modified. if self.pause_loop: self.verify_pause_loop = True while self.pause_loop: time.sleep(0.1) if self.trigger_type == 'trigger_infrared_remote_input': self.infrared_remote_input() elif (self.is_activated and self.timer_period and self.timer_period < time.time()): check_approved = False # Check if the trigger period has elapsed if self.trigger_type in [ 'trigger_sunrise_sunset', 'trigger_run_pwm_method' ]: while self.running and self.timer_period < time.time(): self.timer_period = calculate_sunrise_sunset_epoch( self.trigger) if self.trigger_type == 'trigger_run_pwm_method': # Only execute trigger actions when started # Now only set PWM output pwm_duty_cycle, ended = self.get_method_output( self.unique_id_1) if not ended: output_channel = OutputChannel.query.filter( OutputChannel.unique_id == self.trigger.unique_id_3).first() self.set_output_duty_cycle( self.unique_id_2, pwm_duty_cycle, output_channel=output_channel.channel) if self.trigger_actions_at_period: trigger_function_actions( self.unique_id, debug=self.log_level_debug) else: check_approved = True elif (self.trigger_type in [ 'trigger_timer_daily_time_point', 'trigger_timer_daily_time_span', 'trigger_timer_duration' ]): if self.trigger_type == 'trigger_timer_daily_time_point': self.timer_period = epoch_of_next_time( '{hm}:00'.format(hm=self.timer_start_time)) elif self.trigger_type in [ 'trigger_timer_duration', 'trigger_timer_daily_time_span' ]: while self.running and self.timer_period < time.time(): self.timer_period += self.period check_approved = True if check_approved: self.attempt_execute(self.check_triggers)
def receive_infrared_code_broadcast(self, code): if self.word in code: timestamp = datetime.datetime.fromtimestamp( time.time()).strftime('%Y-%m-%d %H:%M:%S') message = "{ts}\n[Trigger {id} ({name})]".format( ts=timestamp, name=self.trigger_name, id=self.function_id) message += "\nInfrared Remote Input detected " \ "'{word}' on program '{prog}'".format( word=self.word, prog=self.program) trigger_function_actions(self.function_id, message=message)
def trigger_all_actions( self, function_id, message=''): try: return trigger_function_actions(function_id, message=message) except Exception as except_msg: message = "Could not trigger Conditional Actions:" \ " {err}".format(err=except_msg) self.logger.exception(message)
def check_triggers(self): """ Check if any Triggers are activated and execute their actions if so. For example, if measured temperature is above 30C, notify [email protected] "if measured temperature is above 30C" is the Trigger to check. "notify [email protected]" is the Trigger Action to execute if the Trigger is True. """ now = time.time() timestamp = datetime.datetime.fromtimestamp(now).strftime( '%Y-%m-%d %H:%M:%S') message = "{ts}\n[Trigger {id} ({name})]".format( ts=timestamp, name=self.trigger_name, id=self.unique_id) trigger = db_retrieve_table_daemon( Trigger, unique_id=self.unique_id, entry='first') device_id = trigger.measurement.split(',')[0] # if len(trigger.measurement.split(',')) > 1: # device_measurement = trigger.measurement.split(',')[1] # else: # device_measurement = None device = None input_dev = db_retrieve_table_daemon( Input, unique_id=device_id, entry='first') if input_dev: device = input_dev math = db_retrieve_table_daemon( Math, unique_id=device_id, entry='first') if math: device = math output = db_retrieve_table_daemon( Output, unique_id=device_id, entry='first') if output: device = output pid = db_retrieve_table_daemon( PID, unique_id=device_id, entry='first') if pid: device = pid if not device: message += " Error: Controller not Input, Math, Output, or PID" self.logger.error(message) return # If the edge detection variable is set, calling this function will # trigger an edge detection event. This will merely produce the correct # message based on the edge detection settings. elif trigger.trigger_type == 'trigger_edge': try: GPIO.setmode(GPIO.BCM) GPIO.setup(int(input_dev.pin), GPIO.IN) gpio_state = GPIO.input(int(input_dev.pin)) except: gpio_state = None self.logger.error("Exception reading the GPIO pin") if (gpio_state is not None and gpio_state == trigger.if_sensor_gpio_state): message += " GPIO State Detected (state = {state}).".format( state=trigger.if_sensor_gpio_state) else: self.logger.error("GPIO not configured correctly or GPIO state not verified") return # Calculate the sunrise/sunset times and find the next time this trigger should trigger elif trigger.trigger_type == 'trigger_sunrise_sunset': # Since the check time is the trigger time, we will only calculate and set the next trigger time self.timer_period = calculate_sunrise_sunset_epoch(trigger) # Check if the current time is between the start and end time elif trigger.trigger_type == 'trigger_timer_daily_time_span': if not time_between_range(self.timer_start_time, self.timer_end_time): return # If the code hasn't returned by now, action should be executed trigger_function_actions( self.unique_id, message=message, debug=self.log_level_debug)
def initialize_variables(self): """ Define all settings """ self.email_count = 0 self.allowed_to_send_notice = True self.sample_rate = db_retrieve_table_daemon( Misc, entry='first').sample_rate_controller_conditional self.smtp_max_count = db_retrieve_table_daemon( SMTP, entry='first').hourly_max self.trigger = db_retrieve_table_daemon( Trigger, unique_id=self.unique_id) self.trigger_type = self.trigger.trigger_type self.trigger_name = self.trigger.name self.is_activated = self.trigger.is_activated self.log_level_debug = self.trigger.log_level_debug self.set_log_level_debug(self.log_level_debug) now = time.time() self.smtp_wait_timer = now + 3600 self.timer_period = None # Set up trigger timer (daily time point) if self.trigger_type == 'trigger_timer_daily_time_point': self.timer_start_time = self.trigger.timer_start_time self.timer_period = epoch_of_next_time( '{hm}:00'.format(hm=self.trigger.timer_start_time)) # Set up trigger timer (daily time span) elif self.trigger_type == 'trigger_timer_daily_time_span': self.timer_start_time = self.trigger.timer_start_time self.timer_end_time = self.trigger.timer_end_time self.period = self.trigger.period self.timer_period = now # Set up trigger timer (duration) elif self.trigger_type == 'trigger_timer_duration': self.period = self.trigger.period if self.trigger.timer_start_offset: self.timer_period = now + self.trigger.timer_start_offset else: self.timer_period = now # Set up trigger Run PWM Method elif self.trigger_type == 'trigger_run_pwm_method': self.unique_id_1 = self.trigger.unique_id_1 self.unique_id_2 = self.trigger.unique_id_2 self.period = self.trigger.period self.trigger_actions_at_period = self.trigger.trigger_actions_at_period self.trigger_actions_at_start = self.trigger.trigger_actions_at_start self.method_start_time = self.trigger.method_start_time self.method_end_time = self.trigger.method_end_time if self.is_activated: self.start_method(self.trigger.unique_id_1) if self.trigger_actions_at_start: self.timer_period = now + self.trigger.period if self.is_activated: pwm_duty_cycle = self.get_method_output( self.trigger.unique_id_1) self.set_output_duty_cycle( self.trigger.unique_id_2, pwm_duty_cycle) trigger_function_actions(self.unique_id, debug=self.log_level_debug) else: self.timer_period = now elif self.trigger_type == 'trigger_infrared_remote_input': import lirc self.lirc = lirc self.program = self.trigger.program self.word = self.trigger.word lirc.init(self.program, config_filename='/home/pi/.lircrc', blocking=False) # Set up trigger sunrise/sunset elif self.trigger_type == 'trigger_sunrise_sunset': self.period = 60 # Set the next trigger at the specified sunrise/sunset time (+-offsets) self.timer_period = calculate_sunrise_sunset_epoch(self.trigger)
def run(self): try: self.running = True self.logger.info("Activated in {:.1f} ms".format( (timeit.default_timer() - self.thread_startup_timer) * 1000)) self.ready.set() while self.running: # Pause loop to modify trigger. # Prevents execution of trigger while variables are # being modified. if self.pause_loop: self.verify_pause_loop = True while self.pause_loop: time.sleep(0.1) if self.trigger_type == 'trigger_infrared_remote_input': self.infrared_remote_input() elif (self.is_activated and self.timer_period and self.timer_period < time.time()): check_approved = False # Check if the trigger period has elapsed if self.trigger_type in [ 'trigger_sunrise_sunset', 'trigger_run_pwm_method' ]: while self.running and self.timer_period < time.time(): self.timer_period += self.period if self.trigger_type == 'trigger_run_pwm_method': # Only execute trigger actions when started # Now only set PWM output pwm_duty_cycle, ended = self.get_method_output( self.unique_id_1) if not ended: self.set_output_duty_cycle( self.unique_id_2, pwm_duty_cycle) if self.trigger_actions_at_period: trigger_function_actions( self.function_id, debug=self.log_level_debug) else: check_approved = True elif (self.trigger_type in [ 'trigger_timer_daily_time_point', 'trigger_timer_daily_time_span', 'trigger_timer_duration' ]): if self.trigger_type == 'trigger_timer_daily_time_point': self.timer_period = epoch_of_next_time( '{hm}:00'.format(hm=self.timer_start_time)) elif self.trigger_type in [ 'trigger_timer_duration', 'trigger_timer_daily_time_span' ]: while self.running and self.timer_period < time.time( ): self.timer_period += self.period check_approved = True if check_approved: self.check_triggers() time.sleep(self.sample_rate) self.running = False self.logger.info("Deactivated in {:.1f} ms".format( (timeit.default_timer() - self.thread_shutdown_timer) * 1000)) except Exception as except_msg: self.logger.exception("Run Error: {err}".format(err=except_msg))
def check_triggers(self): """ Check if any Triggers are activated and execute their actions if so. For example, if measured temperature is above 30C, notify [email protected] "if measured temperature is above 30C" is the Trigger to check. "notify [email protected]" is the Trigger Action to execute if the Trigger is True. """ last_measurement = None gpio_state = None logger_cond = logging.getLogger("mycodo.conditional_{id}".format( id=self.function_id)) trigger = db_retrieve_table_daemon( Trigger, unique_id=self.function_id, entry='first') now = time.time() timestamp = datetime.datetime.fromtimestamp(now).strftime('%Y-%m-%d %H:%M:%S') message = "{ts}\n[Trigger {id} ({name})]".format( ts=timestamp, name=trigger.name, id=self.function_id) device_id = trigger.measurement.split(',')[0] if len(trigger.measurement.split(',')) > 1: device_measurement = trigger.measurement.split(',')[1] else: device_measurement = None device = None input_dev = db_retrieve_table_daemon( Input, unique_id=device_id, entry='first') if input_dev: device = input_dev math = db_retrieve_table_daemon( Math, unique_id=device_id, entry='first') if math: device = math output = db_retrieve_table_daemon( Output, unique_id=device_id, entry='first') if output: device = output pid = db_retrieve_table_daemon( PID, unique_id=device_id, entry='first') if pid: device = pid if not device: message += " Error: Controller not Input, Math, Output, or PID" logger_cond.error(message) return # If the edge detection variable is set, calling this function will # trigger an edge detection event. This will merely produce the correct # message based on the edge detection settings. elif trigger.trigger_type == 'trigger_edge': try: GPIO.setmode(GPIO.BCM) GPIO.setup(int(input_dev.pin), GPIO.IN) gpio_state = GPIO.input(int(input_dev.pin)) except: gpio_state = None logger_cond.error("Exception reading the GPIO pin") if (gpio_state is not None and gpio_state == trigger.if_sensor_gpio_state): message += " GPIO State Detected (state = {state}).".format( state=trigger.if_sensor_gpio_state) else: logger_cond.error("GPIO not configured correctly or GPIO state not verified") return # Calculate the sunrise/sunset times and find the next time this trigger should trigger elif trigger.trigger_type == 'trigger_sunrise_sunset': # Since the check time is the trigger time, we will only calculate and set the next trigger time self.timer_period = calculate_sunrise_sunset_epoch(trigger) # Check if the current time is between the start and end time if trigger.trigger_type == 'trigger_timer_daily_time_span': if not time_between_range(self.timer_start_time, self.timer_end_time): return # If the code hasn't returned by now, action should be executed trigger_function_actions(self.function_id, message=message)
def setup_settings(self): """ Define all settings """ trigger = db_retrieve_table_daemon( Trigger, unique_id=self.function_id) self.trigger_type = trigger.trigger_type self.is_activated = trigger.is_activated self.smtp_max_count = db_retrieve_table_daemon( SMTP, entry='first').hourly_max self.email_count = 0 self.allowed_to_send_notice = True now = time.time() self.smtp_wait_timer = now + 3600 self.timer_period = None # Set up trigger timer (daily time point) if self.trigger_type == 'trigger_timer_daily_time_point': self.timer_start_time = trigger.timer_start_time self.timer_period = epoch_of_next_time( '{hm}:00'.format(hm=trigger.timer_start_time)) # Set up trigger timer (daily time span) elif self.trigger_type == 'trigger_timer_daily_time_span': self.timer_start_time = trigger.timer_start_time self.timer_end_time = trigger.timer_end_time self.period = trigger.period self.timer_period = now # Set up trigger timer (duration) elif self.trigger_type == 'trigger_timer_duration': self.period = trigger.period if trigger.timer_start_offset: self.timer_period = now + trigger.timer_start_offset else: self.timer_period = now # Set up trigger Run PWM Method elif self.trigger_type == 'trigger_run_pwm_method': self.unique_id_1 = trigger.unique_id_1 self.unique_id_2 = trigger.unique_id_2 self.period = trigger.period self.trigger_actions_at_period = trigger.trigger_actions_at_period self.trigger_actions_at_start = trigger.trigger_actions_at_start self.method_start_time = trigger.method_start_time self.method_end_time = trigger.method_end_time if self.is_activated: self.start_method(trigger.unique_id_1) if self.trigger_actions_at_start: self.timer_period = now + trigger.period if self.is_activated: pwm_duty_cycle = self.get_method_output( trigger.unique_id_1) self.set_output_duty_cycle( trigger.unique_id_2, pwm_duty_cycle) trigger_function_actions(self.function_id) else: self.timer_period = now # Set up trigger sunrise/sunset elif self.trigger_type == 'trigger_sunrise_sunset': self.period = 60 # Set the next trigger at the specified sunrise/sunset time (+-offsets) self.timer_period = calculate_sunrise_sunset_epoch(trigger)
def run(self): try: self.running = True self.logger.info( "Activated in {:.1f} ms".format( (timeit.default_timer() - self.thread_startup_timer) * 1000)) self.ready.set() while self.running: # Pause loop to modify trigger. # Prevents execution of trigger while variables are # being modified. if self.pause_loop: self.verify_pause_loop = True while self.pause_loop: time.sleep(0.1) if (self.is_activated and self.timer_period and self.timer_period < time.time()): check_approved = False # Check if the trigger period has elapsed if self.trigger_type in ['trigger_sunrise_sunset', 'trigger_run_pwm_method']: while self.running and self.timer_period < time.time(): self.timer_period += self.period if self.trigger_type == 'trigger_run_pwm_method': # Only execute trigger actions when started # Now only set PWM output pwm_duty_cycle, ended = self.get_method_output( self.unique_id_1) if not ended: self.set_output_duty_cycle( self.unique_id_2, pwm_duty_cycle) if self.trigger_actions_at_period: trigger_function_actions(self.function_id) else: check_approved = True elif (self.trigger_type in [ 'trigger_timer_daily_time_point', 'trigger_timer_daily_time_span', 'trigger_timer_duration']): if self.trigger_type == 'trigger_timer_daily_time_point': self.timer_period = epoch_of_next_time( '{hm}:00'.format(hm=self.timer_start_time)) elif self.trigger_type in ['trigger_timer_duration', 'trigger_timer_daily_time_span']: while self.running and self.timer_period < time.time(): self.timer_period += self.period check_approved = True if check_approved: self.check_triggers() time.sleep(self.sample_rate) self.running = False self.logger.info( "Deactivated in {:.1f} ms".format( (timeit.default_timer() - self.thread_shutdown_timer) * 1000)) except Exception as except_msg: self.logger.exception("Run Error: {err}".format( err=except_msg))