def initialize_variables(self): """ Define all settings """ cond = db_retrieve_table_daemon(Conditional, unique_id=self.unique_id) self.is_activated = cond.is_activated self.conditional_statement = cond.conditional_statement self.period = cond.period self.start_offset = cond.start_offset self.log_level_debug = cond.log_level_debug self.message_include_code = cond.message_include_code self.set_log_level_debug(self.log_level_debug) now = time.time() self.timer_period = now + self.start_offset self.file_run = '{}/conditional_{}.py'.format(PATH_PYTHON_CODE_USER, self.unique_id) # If the file to execute doesn't exist, generate it if not os.path.exists(self.file_run): save_conditional_code( [], self.conditional_statement, self.unique_id, db_retrieve_table_daemon(ConditionalConditions, entry='all'), db_retrieve_table_daemon(Actions, entry='all')) module_name = "mycodo.conditional.{}".format( os.path.basename(self.file_run).split('.')[0]) spec = importlib.util.spec_from_file_location(module_name, self.file_run) conditional_run = importlib.util.module_from_spec(spec) spec.loader.exec_module(conditional_run) self.conditional_run = conditional_run.ConditionalRun( self.logger, self.unique_id, '')
def initialize_variables(self): """Define all settings.""" cond = db_retrieve_table_daemon( Conditional, unique_id=self.unique_id) self.is_activated = cond.is_activated self.conditional_statement = cond.conditional_statement self.conditional_status = cond.conditional_status self.period = cond.period self.start_offset = cond.start_offset self.pyro_timeout = cond.pyro_timeout self.log_level_debug = cond.log_level_debug self.message_include_code = cond.message_include_code self.sample_rate = db_retrieve_table_daemon( Misc, entry='first').sample_rate_controller_conditional self.set_log_level_debug(self.log_level_debug) now = time.time() self.timer_period = now + self.start_offset self.file_run = f'{PATH_PYTHON_CODE_USER}/conditional_{self.unique_id}.py' # If the file to execute doesn't exist, generate it if not os.path.exists(self.file_run): save_conditional_code( [], self.conditional_statement, self.conditional_status, self.unique_id, db_retrieve_table_daemon(ConditionalConditions, entry='all'), db_retrieve_table_daemon(Actions, entry='all'), timeout=self.pyro_timeout) module_name = f"mycodo.conditional.{os.path.basename(self.file_run).split('.')[0]}" spec = importlib.util.spec_from_file_location( module_name, self.file_run) conditional_run = importlib.util.module_from_spec(spec) spec.loader.exec_module(conditional_run) self.conditional_run = conditional_run.ConditionalRun( self.logger, self.unique_id, '') self.logger.debug( f"Conditional Statement (pre-replacement):\n{self.conditional_statement}") with open(self.file_run, 'r') as file: self.logger.debug( f"Conditional Statement (post-replacement):\n{file.read()}") self.ready.set() self.running = True
def conditional_mod(form): """Modify a Conditional""" error = [] action = '{action} {controller}'.format( action=TRANSLATIONS['modify']['title'], controller=TRANSLATIONS['conditional']['title']) try: error, lines_code, cmd_status, cmd_out = save_conditional_code( error, form.conditional_statement.data, form.function_id.data, ConditionalConditions.query.all(), Actions.query.all(), test=True) message = Markup( '<pre>\n\n' 'Full Conditional Statement code:\n\n{code}\n\n' 'Conditional Statement code analysis:\n\n{report}' '</pre>'.format( code=lines_code, report=cmd_out.decode("utf-8"))) cond_mod = Conditional.query.filter( Conditional.unique_id == form.function_id.data).first() cond_mod.name = form.name.data cond_mod.conditional_statement = form.conditional_statement.data cond_mod.period = form.period.data cond_mod.log_level_debug = form.log_level_debug.data cond_mod.message_include_code = form.message_include_code.data cond_mod.start_offset = form.start_offset.data if cmd_status: flash("pylint returned with status: {}".format(cmd_status), "warning") if message: flash("Review your code for issues and test before putting it " "into a production environment.", 'info') flash(message, 'info') if not error: db.session.commit() if cond_mod.is_activated: control = DaemonControl() return_value = control.refresh_daemon_conditional_settings( form.function_id.data) flash(gettext( "Daemon response: %(resp)s", resp=return_value), "success") except sqlalchemy.exc.OperationalError as except_msg: error.append(except_msg) except sqlalchemy.exc.IntegrityError as except_msg: error.append(except_msg) except Exception as except_msg: error.append(except_msg) flash_success_errors(error, action, url_for('routes_page.page_function'))
with session_scope(MYCODO_DB_PATH) as cond_sess: for each_cond in cond_sess.query(Conditional).all(): error = [] each_cond.conditional_statement = each_cond.conditional_statement.replace( 'self.measure(', 'self.condition(') each_cond.conditional_statement = each_cond.conditional_statement.replace( 'self.measure_dict(', 'self.condition_dict(') if not error: cond_sess.commit() else: for each_error in error: print("Error: {}".format(each_error)) save_conditional_code( [], each_cond.conditional_statement, each_cond.unique_is, conditions, actions) except Exception: msg = "ERROR: post-alembic revision {}: {}".format( each_revision, traceback.format_exc()) error.append(msg) print(msg) elif each_revision == '545744b31813': print("Executing post-alembic code for revision {}".format( each_revision)) try: from mycodo.databases.models import Output with session_scope(MYCODO_DB_PATH) as output_sess:
def conditional_mod(form): """Modify a Conditional.""" messages = { "success": [], "info": [], "warning": [], "error": [], "page_refresh": True, "return_text": [], "name": None } try: if current_app.config['TESTING']: cmd_status = None pylint_message = "" else: messages[ "error"], lines_code, cmd_status, cmd_out = save_conditional_code( messages["error"], form.conditional_statement.data, form.conditional_status.data, form.function_id.data, ConditionalConditions.query.all(), Actions.query.all(), timeout=form.pyro_timeout.data, test=True) pylint_message = Markup( '<pre>\n\n' 'Full Conditional Statement code:\n\n{code}\n\n' 'Conditional Statement code analysis:\n\n{report}' '</pre>'.format(code=lines_code, report=cmd_out.decode("utf-8"))) cond_mod = Conditional.query.filter( Conditional.unique_id == form.function_id.data).first() cond_mod.name = form.name.data messages["name"] = form.name.data cond_mod.conditional_statement = form.conditional_statement.data cond_mod.conditional_status = form.conditional_status.data cond_mod.period = form.period.data cond_mod.log_level_debug = form.log_level_debug.data cond_mod.message_include_code = form.message_include_code.data cond_mod.start_offset = form.start_offset.data cond_mod.pyro_timeout = form.pyro_timeout.data if cmd_status: messages["warning"].append( "pylint returned with status: {}".format(cmd_status)) if pylint_message: messages["info"].append( "Review your code for issues and test before putting it " "into a production environment.") messages["return_text"].append(pylint_message) if not messages["error"]: db.session.commit() messages["success"].append('{action} {controller}'.format( action=TRANSLATIONS['modify']['title'], controller=TRANSLATIONS['conditional']['title'])) if cond_mod.is_activated: control = DaemonControl() return_value = control.refresh_daemon_conditional_settings( form.function_id.data) messages["success"].append( gettext("Daemon response: %(resp)s", resp=return_value)) except sqlalchemy.exc.OperationalError as except_msg: messages["error"].append(str(except_msg)) except sqlalchemy.exc.IntegrityError as except_msg: messages["error"].append(str(except_msg)) except Exception as except_msg: messages["error"].append(str(except_msg)) return messages
def function_add(form_add_func): action = '{action} {controller}'.format( action=TRANSLATIONS['add']['title'], controller=TRANSLATIONS['function']['title']) error = [] function_name = form_add_func.function_type.data dict_controllers = parse_function_information() if current_app.config['TESTING']: dep_unmet = False else: dep_unmet, _ = return_dependencies(function_name) if dep_unmet: list_unmet_deps = [] for each_dep in dep_unmet: list_unmet_deps.append(each_dep[0]) error.append( "The {dev} device you're trying to add has unmet " "dependencies: {dep}".format(dev=function_name, dep=', '.join(list_unmet_deps))) new_func = None try: if function_name == 'conditional_conditional': new_func = Conditional() new_func.conditional_statement = ''' # Example code for learning how to use a Conditional. See the manual for more information. self.logger.info("This INFO log entry will appear in the Daemon Log") self.logger.error("This ERROR log entry will appear in the Daemon Log") # Replace "asdf1234" with a Condition ID measurement = self.condition("{asdf1234}") self.logger.info("Check this measurement in the Daemon Log. The value is {val}".format(val=measurement)) if measurement is not None: # If a measurement exists self.message += "This message appears in email alerts and notes.\\n" if measurement < 23: # If the measurement is less than 23 self.message += "Measurement is too Low! Measurement is {meas}\\n".format(meas=measurement) self.run_all_actions(message=self.message) # Run all actions sequentially elif measurement > 27: # Else If the measurement is greater than 27 self.message += "Measurement is too High! Measurement is {meas}\\n".format(meas=measurement) # Replace "qwer5678" with an Action ID self.run_action("{qwer5678}", message=self.message) # Run a single specific Action''' if not error: new_func.save() save_conditional_code(error, new_func.conditional_statement, new_func.unique_id, ConditionalConditions.query.all(), Actions.query.all(), test=False) elif function_name == 'pid_pid': new_func = PID().save() for each_channel, measure_info in PID_INFO['measure'].items(): new_measurement = DeviceMeasurements() if 'name' in measure_info: new_measurement.name = measure_info['name'] if 'measurement_type' in measure_info: new_measurement.measurement_type = measure_info[ 'measurement_type'] new_measurement.device_id = new_func.unique_id new_measurement.measurement = measure_info['measurement'] new_measurement.unit = measure_info['unit'] new_measurement.channel = each_channel if not error: new_measurement.save() elif function_name in [ 'trigger_edge', 'trigger_output', 'trigger_output_pwm', 'trigger_timer_daily_time_point', 'trigger_timer_daily_time_span', 'trigger_timer_duration', 'trigger_infrared_remote_input', 'trigger_run_pwm_method', 'trigger_sunrise_sunset' ]: new_func = Trigger() new_func.name = '{}'.format(FUNCTION_INFO[function_name]['name']) new_func.trigger_type = function_name if not error: new_func.save() elif function_name in ['function_spacer', 'function_actions']: new_func = Function() if function_name == 'function_spacer': new_func.name = 'Spacer' new_func.function_type = function_name if not error: new_func.save() elif function_name in dict_controllers: # Custom Function Controller new_func = CustomController() new_func.device = function_name if 'function_name' in dict_controllers[function_name]: new_func.name = dict_controllers[function_name][ 'function_name'] else: new_func.name = 'Function Name' # TODO: Switch to JSON function list_options = [] if 'custom_options' in dict_controllers[function_name]: for each_option in dict_controllers[function_name][ 'custom_options']: if 'id' not in each_option: continue if each_option['default_value'] is False: default_value = '' else: default_value = each_option['default_value'] option = '{id},{value}'.format(id=each_option['id'], value=default_value) list_options.append(option) new_func.custom_options = ';'.join(list_options) if not error: new_func.save() elif function_name == '': error.append("Must select a function type") else: error.append("Unknown function type: '{}'".format(function_name)) if not error: display_order = csv_to_list_of_str( DisplayOrder.query.first().function) DisplayOrder.query.first().function = add_display_order( display_order, new_func.unique_id) db.session.commit() except sqlalchemy.exc.OperationalError as except_msg: error.append(except_msg) except sqlalchemy.exc.IntegrityError as except_msg: error.append(except_msg) except Exception as except_msg: error.append(except_msg) flash_success_errors(error, action, url_for('routes_page.page_function')) if dep_unmet: return 1
def function_add(form_add_func): messages = {"success": [], "info": [], "warning": [], "error": []} new_function_id = None list_unmet_deps = [] dep_name = None dep_message = '' function_name = form_add_func.function_type.data dict_controllers = parse_function_information() if not current_app.config['TESTING']: dep_unmet, _, dep_message = return_dependencies(function_name) if dep_unmet: for each_dep in dep_unmet: list_unmet_deps.append(each_dep[3]) messages["error"].append( f"{function_name} has unmet dependencies. " "They must be installed before the Function can be added.") if function_name in dict_controllers: dep_name = dict_controllers[function_name]['function_name'] else: messages["error"].append( f"Function not found: {function_name}") return messages, dep_name, list_unmet_deps, dep_message, None new_func = None try: if function_name == 'conditional_conditional': new_func = Conditional() new_func.position_y = 999 new_func.conditional_statement = ''' # Example code for learning how to use a Conditional. See the manual for more information. self.logger.info("This INFO log entry will appear in the Daemon Log") self.logger.error("This ERROR log entry will appear in the Daemon Log") if not hasattr(self, "loop_count"): # Initialize objects saved across executions self.loop_count = 1 else: self.loop_count += 1 # Replace "asdf1234" with a Condition ID measurement = self.condition("{asdf1234}") self.logger.info(f"Check this measurement in the Daemon Log. The value is {measurement}") if measurement is not None: # If a measurement exists self.message += "This message appears in email alerts and notes.\\n" if measurement < 23: # If the measurement is less than 23 self.message += f"Measurement is too Low! Measurement is {measurement}\\n" self.run_all_actions(message=self.message) # Run all actions sequentially elif measurement > 27: # Else If the measurement is greater than 27 self.message += f"Measurement is too High! Measurement is {measurement}\\n" # Replace "qwer5678" with an Action ID self.run_action("{qwer5678}", message=self.message) # Run a single specific Action''' new_func.conditional_status = ''' # Example code to provide a return status for other controllers and widgets. status_dict = { 'string_status': f"This is the demo status of the conditional controller. " f"The controller has looped {self.loop_count} times", 'loop_count': self.loop_count, 'error': [] } return status_dict''' if not messages["error"]: new_func.save() new_function_id = new_func.unique_id if not current_app.config['TESTING']: save_conditional_code(messages["error"], new_func.conditional_statement, new_func.conditional_status, new_func.unique_id, ConditionalConditions.query.all(), Actions.query.all(), test=False) elif function_name == 'pid_pid': new_func = PID() new_func.position_y = 999 new_func.save() new_function_id = new_func.unique_id for each_channel, measure_info in PID_INFO['measure'].items(): new_measurement = DeviceMeasurements() if 'name' in measure_info: new_measurement.name = measure_info['name'] if 'measurement_type' in measure_info: new_measurement.measurement_type = measure_info[ 'measurement_type'] new_measurement.device_id = new_func.unique_id new_measurement.measurement = measure_info['measurement'] new_measurement.unit = measure_info['unit'] new_measurement.channel = each_channel if not messages["error"]: new_measurement.save() elif function_name in [ 'trigger_edge', 'trigger_output', 'trigger_output_pwm', 'trigger_timer_daily_time_point', 'trigger_timer_daily_time_span', 'trigger_timer_duration', 'trigger_run_pwm_method', 'trigger_sunrise_sunset' ]: new_func = Trigger() new_func.name = '{}'.format(FUNCTION_INFO[function_name]['name']) new_func.trigger_type = function_name new_func.position_y = 999 if not messages["error"]: new_func.save() new_function_id = new_func.unique_id elif function_name == 'function_actions': new_func = Function() new_func.position_y = 999 new_func.function_type = function_name if not messages["error"]: new_func.save() new_function_id = new_func.unique_id elif function_name in dict_controllers: # Custom Function Controller new_func = CustomController() new_func.device = function_name new_func.position_y = 999 if 'function_name' in dict_controllers[function_name]: new_func.name = dict_controllers[function_name][ 'function_name'] else: new_func.name = 'Function Name' # Generate string to save from custom options messages["error"], custom_options = custom_options_return_json( messages["error"], dict_controllers, device=function_name, use_defaults=True) new_func.custom_options = custom_options new_func.unique_id = set_uuid() if ('execute_at_creation' in dict_controllers[new_func.device] and not current_app.config['TESTING']): messages["error"], new_func = dict_controllers[ new_func.device]['execute_at_creation']( messages["error"], new_func, dict_controllers[new_func.device]) if not messages["error"]: new_func.save() new_function_id = new_func.unique_id elif function_name == '': messages["error"].append("Must select a function type") else: messages["error"].append( f"Unknown function type: '{function_name}'") if not messages["error"]: if function_name in dict_controllers: # # Add measurements defined in the Function Module # if ('measurements_dict' in dict_controllers[function_name] and dict_controllers[function_name]['measurements_dict']): for each_channel in dict_controllers[function_name][ 'measurements_dict']: measure_info = dict_controllers[function_name][ 'measurements_dict'][each_channel] new_measurement = DeviceMeasurements() new_measurement.device_id = new_func.unique_id if 'name' in measure_info: new_measurement.name = measure_info['name'] else: new_measurement.name = "" if 'measurement' in measure_info: new_measurement.measurement = measure_info[ 'measurement'] else: new_measurement.measurement = "" if 'unit' in measure_info: new_measurement.unit = measure_info['unit'] else: new_measurement.unit = "" new_measurement.channel = each_channel new_measurement.save() # # If there are a variable number of measurements # elif ('measurements_variable_amount' in dict_controllers[function_name] and dict_controllers[function_name] ['measurements_variable_amount']): # Add first default measurement with empty unit and measurement new_measurement = DeviceMeasurements() new_measurement.name = "" new_measurement.device_id = new_func.unique_id new_measurement.measurement = "" new_measurement.unit = "" new_measurement.channel = 0 new_measurement.save() # # Add channels defined in the Function Module # if 'channels_dict' in dict_controllers[function_name]: for each_channel, channel_info in dict_controllers[ function_name]['channels_dict'].items(): new_channel = FunctionChannel() new_channel.channel = each_channel new_channel.function_id = new_func.unique_id # Generate string to save from custom options messages[ "error"], custom_options = custom_channel_options_return_json( messages["error"], dict_controllers, None, new_func.unique_id, each_channel, device=new_func.device, use_defaults=True) new_channel.custom_options = custom_options new_channel.save() messages["success"].append( f"{TRANSLATIONS['add']['title']} {TRANSLATIONS['function']['title']}" ) except sqlalchemy.exc.OperationalError as except_msg: messages["error"].append(str(except_msg)) except sqlalchemy.exc.IntegrityError as except_msg: messages["error"].append(str(except_msg)) except Exception as except_msg: logger.exception("Add Function") messages["error"].append(str(except_msg)) return messages, dep_name, list_unmet_deps, dep_message, new_function_id
def function_add(form_add_func): action = '{action} {controller}'.format( action=TRANSLATIONS['add']['title'], controller=TRANSLATIONS['function']['title']) error = [] function_name = form_add_func.function_type.data dict_controllers = parse_function_information() if current_app.config['TESTING']: dep_unmet = False else: dep_unmet, _ = return_dependencies(function_name) if dep_unmet: list_unmet_deps = [] for each_dep in dep_unmet: list_unmet_deps.append(each_dep[0]) error.append( "The {dev} device you're trying to add has unmet " "dependencies: {dep}".format( dev=function_name, dep=', '.join(list_unmet_deps))) new_func = None try: if function_name == 'conditional_conditional': new_func = Conditional() new_func.conditional_statement = ''' # Example code for learning how to use a Conditional. See the manual for more information. self.logger.info("This INFO log entry will appear in the Daemon Log") self.logger.error("This ERROR log entry will appear in the Daemon Log") # Replace "asdf1234" with a Condition ID measurement = self.condition("{asdf1234}") self.logger.info("Check this measurement in the Daemon Log. The value is {val}".format(val=measurement)) if measurement is not None: # If a measurement exists self.message += "This message appears in email alerts and notes.\\n" if measurement < 23: # If the measurement is less than 23 self.message += "Measurement is too Low! Measurement is {meas}\\n".format(meas=measurement) self.run_all_actions(message=self.message) # Run all actions sequentially elif measurement > 27: # Else If the measurement is greater than 27 self.message += "Measurement is too High! Measurement is {meas}\\n".format(meas=measurement) # Replace "qwer5678" with an Action ID self.run_action("{qwer5678}", message=self.message) # Run a single specific Action''' if not error: new_func.save() save_conditional_code( error, new_func.conditional_statement, new_func.unique_id, ConditionalConditions.query.all(), Actions.query.all(), test=False) elif function_name == 'pid_pid': new_func = PID().save() for each_channel, measure_info in PID_INFO['measure'].items(): new_measurement = DeviceMeasurements() if 'name' in measure_info: new_measurement.name = measure_info['name'] if 'measurement_type' in measure_info: new_measurement.measurement_type = measure_info['measurement_type'] new_measurement.device_id = new_func.unique_id new_measurement.measurement = measure_info['measurement'] new_measurement.unit = measure_info['unit'] new_measurement.channel = each_channel if not error: new_measurement.save() elif function_name in ['trigger_edge', 'trigger_output', 'trigger_output_pwm', 'trigger_timer_daily_time_point', 'trigger_timer_daily_time_span', 'trigger_timer_duration', 'trigger_run_pwm_method', 'trigger_sunrise_sunset']: new_func = Trigger() new_func.name = '{}'.format(FUNCTION_INFO[function_name]['name']) new_func.trigger_type = function_name if not error: new_func.save() elif function_name in ['function_spacer', 'function_actions']: new_func = Function() if function_name == 'function_spacer': new_func.name = 'Spacer' new_func.function_type = function_name if not error: new_func.save() elif function_name in dict_controllers: # Custom Function Controller new_func = CustomController() new_func.device = function_name if 'function_name' in dict_controllers[function_name]: new_func.name = dict_controllers[function_name]['function_name'] else: new_func.name = 'Function Name' # Generate string to save from custom options error, custom_options = custom_options_return_json( error, dict_controllers, device=function_name, use_defaults=True) new_func.custom_options = custom_options new_func.unique_id = set_uuid() if ('execute_at_creation' in dict_controllers[new_func.device] and not current_app.config['TESTING']): error, new_func = dict_controllers[new_func.device]['execute_at_creation']( error, new_func, dict_controllers[new_func.device]) if not error: new_func.save() elif function_name == '': error.append("Must select a function type") else: error.append("Unknown function type: '{}'".format( function_name)) if not error: display_order = csv_to_list_of_str( DisplayOrder.query.first().function) DisplayOrder.query.first().function = add_display_order( display_order, new_func.unique_id) db.session.commit() if function_name in dict_controllers: # # Add measurements defined in the Function Module # if ('measurements_dict' in dict_controllers[function_name] and dict_controllers[function_name]['measurements_dict']): for each_channel in dict_controllers[function_name]['measurements_dict']: measure_info = dict_controllers[function_name]['measurements_dict'][each_channel] new_measurement = DeviceMeasurements() new_measurement.device_id = new_func.unique_id if 'name' in measure_info: new_measurement.name = measure_info['name'] else: new_measurement.name = "" if 'measurement' in measure_info: new_measurement.measurement = measure_info['measurement'] else: new_measurement.measurement = "" if 'unit' in measure_info: new_measurement.unit = measure_info['unit'] else: new_measurement.unit = "" new_measurement.channel = each_channel new_measurement.save() # # If there are a variable number of measurements # elif ('measurements_variable_amount' in dict_controllers[function_name] and dict_controllers[function_name]['measurements_variable_amount']): # Add first default measurement with empty unit and measurement new_measurement = DeviceMeasurements() new_measurement.name = "" new_measurement.device_id = new_func.unique_id new_measurement.measurement = "" new_measurement.unit = "" new_measurement.channel = 0 new_measurement.save() # # Add channels defined in the Function Module # if 'channels_dict' in dict_controllers[function_name]: for each_channel, channel_info in dict_controllers[function_name]['channels_dict'].items(): new_channel = FunctionChannel() new_channel.channel = each_channel new_channel.function_id = new_func.unique_id # Generate string to save from custom options error, custom_options = custom_channel_options_return_json( error, dict_controllers, None, new_func.unique_id, each_channel, device=new_func.device, use_defaults=True) new_channel.custom_options = custom_options new_channel.save() flash(gettext( "%(type)s Function with ID %(id)s (%(uuid)s) successfully added", type=new_func.name, id=new_func.id, uuid=new_func.unique_id), "success") except sqlalchemy.exc.OperationalError as except_msg: error.append(except_msg) except sqlalchemy.exc.IntegrityError as except_msg: error.append(except_msg) except Exception as except_msg: logger.exception("Add Function") error.append(except_msg) flash_success_errors(error, action, url_for('routes_page.page_function')) if dep_unmet: return 1