def action_mod(form, request_form): """Modify an Action.""" messages = { "success": [], "info": [], "warning": [], "error": [] } mod_action = Actions.query.filter( Actions.unique_id == form.action_id.data).first() if not action_mod: messages["error"].append("Action not found") else: # Parse custom options for action dict_actions = parse_action_information() if mod_action.action_type in dict_actions: messages["error"], custom_options = custom_options_return_json( messages["error"], dict_actions, request_form, mod_dev=mod_action, device=mod_action.action_type) mod_action.custom_options = custom_options if not messages["error"]: try: db.session.commit() messages["success"].append(f"{TRANSLATIONS['modify']['title']} {TRANSLATIONS['actions']['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: messages["error"].append(str(except_msg)) return messages
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) 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 == 'trigger_sunrise_sunset': while self.running and self.timer_period < time.time(): self.timer_period = suntime_calculate_next_sunrise_sunset_epoch( self.trigger.latitude, self.trigger.longitude, self.trigger.date_offset_days, self.trigger.time_offset_minutes, self.trigger.rise_or_set) check_approved = True elif 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.trigger.unique_id_1) self.timer_period += self.trigger.period self.set_output_duty_cycle(pwm_duty_cycle) actions = parse_action_information() if self.trigger_actions_at_period: trigger_controller_actions(actions, self.unique_id, debug=self.log_level_debug) check_approved = True if ended: self.stop_method() 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( f'{self.timer_start_time}:00') 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 test_add_all_function_actions_logged_in_as_admin(_, testapp): """Verifies adding all function actions as a logged in admin user.""" print("\nTest: test_add_all_function_actions_logged_in_as_admin") login_user(testapp, 'admin', '53CR3t_p4zZW0rD') action_count = 0 choices_action = [] dict_actions = parse_action_information() for action in dict_actions: choices_action.append(action) # Add Execute Actions function response = add_function(testapp, function_type="function_actions") assert 'data' in response.json assert 'messages' in response.json['data'] assert 'error' in response.json['data']['messages'] assert response.json['data']['messages']['error'] == [] assert 'success' in response.json['data']['messages'] assert len(response.json['data']['messages']['success']) == 1 function_dev = Function.query.filter(Function.id == 1).first() # Add/delete every action for index, each_action in enumerate(choices_action): print("test_add_all_function_actions_logged_in_as_admin: Adding, saving, and deleting Action ({}/{}): {}".format( index + 1, len(choices_action), each_action)) response = add_action(testapp, function_id=function_dev.unique_id, action_type=each_action) assert 'data' in response.json assert 'messages' in response.json['data'] assert 'error' in response.json['data']['messages'] assert response.json['data']['messages']['error'] == [] assert 'success' in response.json['data']['messages'] assert len(response.json['data']['messages']['success']) == 1 action = Actions.query.first() # Verify data was entered into the database action_count += 1 assert Actions.query.count() == action_count, "Number of Actions doesn't match: In DB {}, Should be: {}".format( Actions.query.count(), action_count) # Delete action response = delete_data(testapp, 'action', device_dev=action) assert 'data' in response.json assert 'messages' in response.json['data'] assert 'error' in response.json['data']['messages'] assert response.json['data']['messages']['error'] == [] assert 'success' in response.json['data']['messages'] assert len(response.json['data']['messages']['success']) == 1 action_count -= 1 # Delete function response = delete_data(testapp, 'function', device_dev=function_dev) assert 'data' in response.json assert 'messages' in response.json['data'] assert 'error' in response.json['data']['messages'] assert response.json['data']['messages']['error'] == [] assert 'success' in response.json['data']['messages'] assert len(response.json['data']['messages']['success']) == 1
def get_installed_apt_dependencies(): met_deps = [] list_dependencies = [ parse_function_information(), parse_action_information(), parse_input_information(), parse_output_information(), parse_widget_information(), CAMERA_INFO, FUNCTION_INFO, METHOD_INFO, DEPENDENCIES_GENERAL ] for each_section in list_dependencies: for device_type in each_section: if 'dependencies_module' in each_section[device_type]: dep_mod = each_section[device_type]['dependencies_module'] for (install_type, package, install_id) in dep_mod: if install_type == 'apt': start = "dpkg-query -W -f='${Status}'" end = '2>/dev/null | grep -c "ok installed"' cmd = "{} {} {}".format(start, package, end) _, _, status = cmd_output(cmd, user='******') if not status and install_id not in met_deps: met_deps.append(install_id) return met_deps
def page_function(): """Display Function page options.""" function_type = request.args.get('function_type', None) function_id = request.args.get('function_id', None) action_id = request.args.get('action_id', None) condition_id = request.args.get('condition_id', None) each_function = None each_action = None each_condition = None function_page_entry = None function_page_options = None controller_type = None if function_type in ['entry', 'options', 'conditions', 'actions'] and function_id != '0': controller_type = determine_controller_type(function_id) if controller_type == "Conditional": each_function = Conditional.query.filter( Conditional.unique_id == function_id).first() function_page_entry = 'pages/function_options/conditional_entry.html' function_page_options = 'pages/function_options/conditional_options.html' elif controller_type == "PID": each_function = PID.query.filter( PID.unique_id == function_id).first() function_page_entry = 'pages/function_options/pid_entry.html' function_page_options = 'pages/function_options/pid_options.html' elif controller_type == "Trigger": each_function = Trigger.query.filter( Trigger.unique_id == function_id).first() function_page_entry = 'pages/function_options/trigger_entry.html' function_page_options = 'pages/function_options/trigger_options.html' elif controller_type == "Function": each_function = Function.query.filter( Function.unique_id == function_id).first() function_page_entry = 'pages/function_options/function_entry.html' function_page_options = 'pages/function_options/function_options.html' elif controller_type == "Function_Custom": each_function = CustomController.query.filter( CustomController.unique_id == function_id).first() function_page_entry = 'pages/function_options/custom_function_entry.html' function_page_options = 'pages/function_options/custom_function_options.html' if function_type == 'actions' and action_id: each_action = Actions.query.filter( Actions.unique_id == action_id).first() if each_action: controller_type = determine_controller_type(each_action.function_id) if function_type == 'conditions'and condition_id: each_condition = ConditionalConditions.query.filter( ConditionalConditions.unique_id == condition_id).first() action = Actions.query.all() camera = Camera.query.all() conditional = Conditional.query.all() conditional_conditions = ConditionalConditions.query.all() function = CustomController.query.all() function_channel = FunctionChannel.query.all() function_dev = Function.query.all() input_dev = Input.query.all() measurement = Measurement.query.all() method = Method.query.all() tags = NoteTags.query.all() output = Output.query.all() output_channel = OutputChannel.query.all() pid = PID.query.all() trigger = Trigger.query.all() unit = Unit.query.all() user = User.query.all() display_order_function = csv_to_list_of_str( DisplayOrder.query.first().function) form_add_function = forms_function.FunctionAdd() form_mod_pid_base = forms_pid.PIDModBase() form_mod_pid_output_raise = forms_pid.PIDModRelayRaise() form_mod_pid_output_lower = forms_pid.PIDModRelayLower() form_mod_pid_pwm_raise = forms_pid.PIDModPWMRaise() form_mod_pid_pwm_lower = forms_pid.PIDModPWMLower() form_mod_pid_value_raise = forms_pid.PIDModValueRaise() form_mod_pid_value_lower = forms_pid.PIDModValueLower() form_mod_pid_volume_raise = forms_pid.PIDModVolumeRaise() form_mod_pid_volume_lower = forms_pid.PIDModVolumeLower() form_function_base = forms_function.FunctionMod() form_trigger = forms_trigger.Trigger() form_conditional = forms_conditional.Conditional() form_conditional_conditions = forms_conditional.ConditionalConditions() form_function = forms_custom_controller.CustomController() form_actions = forms_action.Actions() dict_controllers = parse_function_information() dict_actions = parse_action_information() # Generate all measurement and units used dict_measurements = add_custom_measurements(Measurement.query.all()) dict_units = add_custom_units(Unit.query.all()) dict_outputs = parse_output_information() custom_options_values_controllers = parse_custom_option_values( function, dict_controller=dict_controllers) custom_options_values_function_channels = parse_custom_option_values_function_channels_json( function_channel, dict_controller=function, key_name='custom_channel_options') custom_options_values_actions = {} for each_action_dev in action: try: custom_options_values_actions[each_action_dev.unique_id] = json.loads(each_action_dev.custom_options) except: custom_options_values_actions[each_action_dev.unique_id] = {} # Create lists of built-in and custom functions choices_functions = [] for choice_function in FUNCTIONS: choices_functions.append({'value': choice_function[0], 'item': choice_function[1]}) choices_custom_functions = utils_general.choices_custom_functions() # Combine function lists choices_functions_add = choices_functions + choices_custom_functions # Sort combined list choices_functions_add = sorted(choices_functions_add, key=lambda i: i['item']) custom_commands = {} for choice_function in function: if 'custom_commands' in dict_controllers[choice_function.device]: custom_commands[choice_function.device] = True # Generate Action dropdown for use with Inputs choices_actions = [] list_actions_sorted = generate_form_action_list(dict_actions, application=["functions"]) for name in list_actions_sorted: choices_actions.append((name, dict_actions[name]['name'])) # Create list of choices to be used in dropdown menus choices_function = utils_general.choices_functions( function, dict_units, dict_measurements) choices_input = utils_general.choices_inputs( input_dev, dict_units, dict_measurements) choices_input_devices = utils_general.choices_input_devices(input_dev) choices_method = utils_general.choices_methods(method) choices_output = utils_general.choices_outputs( output, OutputChannel, dict_outputs, dict_units, dict_measurements) choices_output_channels = utils_general.choices_outputs_channels( output, output_channel, dict_outputs) choices_output_channels_measurements = utils_general.choices_outputs_channels_measurements( output, OutputChannel, dict_outputs, dict_units, dict_measurements) choices_pid = utils_general.choices_pids( pid, dict_units, dict_measurements) choices_tag = utils_general.choices_tags(tags) choices_measurements_units = utils_general.choices_measurements_units( measurement, unit) choices_controller_ids = utils_general.choices_controller_ids() actions_dict = { 'conditional': {}, 'trigger': {} } for each_action_dev in action: if (each_action_dev.function_type == 'conditional' and each_action_dev.unique_id not in actions_dict['conditional']): actions_dict['conditional'][each_action_dev.function_id] = True if (each_action_dev.function_type == 'trigger' and each_action_dev.unique_id not in actions_dict['trigger']): actions_dict['trigger'][each_action_dev.function_id] = True conditions_dict = {} for each_cond in conditional_conditions: if each_cond.unique_id not in conditions_dict: conditions_dict[each_cond.conditional_id] = True controllers = [] controllers_all = [('Input', input_dev), ('Conditional', conditional), ('Function', function), ('PID', pid), ('Trigger', trigger)] for each_controller in controllers_all: for each_cont in each_controller[1]: controllers.append((each_controller[0], each_cont.unique_id, each_cont.id, each_cont.name)) # Create dict of Function names names_function = {} all_elements = [conditional, pid, trigger, function_dev, function] for each_element in all_elements: for each_func_name in each_element: names_function[each_func_name.unique_id] = '[{id}] {name}'.format( id=each_func_name.unique_id.split('-')[0], name=each_func_name.name) # Calculate sunrise/sunset times if conditional controller is set up properly sunrise_set_calc = {} for each_trigger in trigger: if each_trigger.trigger_type == 'trigger_sunrise_sunset': sunrise_set_calc[each_trigger.unique_id] = {} if not current_app.config['TESTING']: try: sunrise = suntime_calculate_next_sunrise_sunset_epoch( each_trigger.latitude, each_trigger.longitude, 0, 0, "sunrise", return_dt=True) sunset = suntime_calculate_next_sunrise_sunset_epoch( each_trigger.latitude, each_trigger.longitude, 0, 0, "sunset", return_dt=True) # Adjust for date offset offset_rise = suntime_calculate_next_sunrise_sunset_epoch( each_trigger.latitude, each_trigger.longitude, each_trigger.date_offset_days, each_trigger.time_offset_minutes, "sunrise", return_dt=True) offset_set = suntime_calculate_next_sunrise_sunset_epoch( each_trigger.latitude, each_trigger.longitude, each_trigger.date_offset_days, each_trigger.time_offset_minutes, "sunset", return_dt=True) sunrise_set_calc[each_trigger.unique_id]['sunrise'] = ( sunrise.strftime("%Y-%m-%d %H:%M")) sunrise_set_calc[each_trigger.unique_id]['sunset'] = ( sunset.strftime("%Y-%m-%d %H:%M")) sunrise_set_calc[each_trigger.unique_id]['offset_sunrise'] = ( offset_rise.strftime("%Y-%m-%d %H:%M")) sunrise_set_calc[each_trigger.unique_id]['offset_sunset'] = ( offset_set.strftime("%Y-%m-%d %H:%M")) except: logger.exception(1) sunrise_set_calc[each_trigger.unique_id]['sunrise'] = "ERROR" sunrise_set_calc[each_trigger.unique_id]['sunrise'] = "ERROR" sunrise_set_calc[each_trigger.unique_id]['offset_sunrise'] = "ERROR" sunrise_set_calc[each_trigger.unique_id]['offset_sunset'] = "ERROR" if not function_type: return render_template('pages/function.html', and_=and_, action=action, actions_dict=actions_dict, camera=camera, choices_actions=choices_actions, choices_controller_ids=choices_controller_ids, choices_custom_functions=choices_custom_functions, choices_function=choices_function, choices_functions=choices_functions, choices_functions_add=choices_functions_add, choices_input=choices_input, choices_input_devices=choices_input_devices, choices_measurements_units=choices_measurements_units, choices_method=choices_method, choices_output=choices_output, choices_output_channels=choices_output_channels, choices_output_channels_measurements=choices_output_channels_measurements, choices_pid=choices_pid, choices_tag=choices_tag, conditional_conditions_list=CONDITIONAL_CONDITIONS, conditional=conditional, conditional_conditions=conditional_conditions, conditions_dict=conditions_dict, controllers=controllers, controller_type=controller_type, function=function, function_channel=function_channel, custom_commands=custom_commands, custom_options_values_actions=custom_options_values_actions, custom_options_values_controllers=custom_options_values_controllers, custom_options_values_function_channels=custom_options_values_function_channels, dict_actions=dict_actions, dict_controllers=dict_controllers, dict_measurements=dict_measurements, dict_outputs=dict_outputs, dict_units=dict_units, display_order_function=display_order_function, form_conditional=form_conditional, form_conditional_conditions=form_conditional_conditions, form_function=form_function, form_actions=form_actions, form_add_function=form_add_function, form_function_base=form_function_base, form_mod_pid_base=form_mod_pid_base, form_mod_pid_pwm_raise=form_mod_pid_pwm_raise, form_mod_pid_pwm_lower=form_mod_pid_pwm_lower, form_mod_pid_output_raise=form_mod_pid_output_raise, form_mod_pid_output_lower=form_mod_pid_output_lower, form_mod_pid_value_raise=form_mod_pid_value_raise, form_mod_pid_value_lower=form_mod_pid_value_lower, form_mod_pid_volume_raise=form_mod_pid_volume_raise, form_mod_pid_volume_lower=form_mod_pid_volume_lower, form_trigger=form_trigger, function_dev=function_dev, function_types=FUNCTIONS, input=input_dev, method=method, names_function=names_function, output=output, output_types=output_types(), pid=pid, sunrise_set_calc=sunrise_set_calc, table_conversion=Conversion, table_device_measurements=DeviceMeasurements, table_input=Input, table_output=Output, tags=tags, trigger=trigger, units=MEASUREMENTS, user=user) elif function_type == 'entry': return render_template(function_page_entry, and_=and_, action=action, actions_dict=actions_dict, camera=camera, choices_actions=choices_actions, choices_controller_ids=choices_controller_ids, choices_custom_functions=choices_custom_functions, choices_function=choices_function, choices_functions=choices_functions, choices_functions_add=choices_functions_add, choices_input=choices_input, choices_input_devices=choices_input_devices, choices_measurements_units=choices_measurements_units, choices_method=choices_method, choices_output=choices_output, choices_output_channels=choices_output_channels, choices_output_channels_measurements=choices_output_channels_measurements, choices_pid=choices_pid, choices_tag=choices_tag, conditional_conditions_list=CONDITIONAL_CONDITIONS, conditional=conditional, conditional_conditions=conditional_conditions, conditions_dict=conditions_dict, controllers=controllers, controller_type=controller_type, function=function, function_channel=function_channel, custom_commands=custom_commands, custom_options_values_actions=custom_options_values_actions, custom_options_values_controllers=custom_options_values_controllers, custom_options_values_function_channels=custom_options_values_function_channels, dict_actions=dict_actions, dict_controllers=dict_controllers, dict_measurements=dict_measurements, dict_outputs=dict_outputs, dict_units=dict_units, display_order_function=display_order_function, each_function=each_function, form_conditional=form_conditional, form_conditional_conditions=form_conditional_conditions, form_function=form_function, form_actions=form_actions, form_add_function=form_add_function, form_function_base=form_function_base, form_mod_pid_base=form_mod_pid_base, form_mod_pid_pwm_raise=form_mod_pid_pwm_raise, form_mod_pid_pwm_lower=form_mod_pid_pwm_lower, form_mod_pid_output_raise=form_mod_pid_output_raise, form_mod_pid_output_lower=form_mod_pid_output_lower, form_mod_pid_value_raise=form_mod_pid_value_raise, form_mod_pid_value_lower=form_mod_pid_value_lower, form_mod_pid_volume_raise=form_mod_pid_volume_raise, form_mod_pid_volume_lower=form_mod_pid_volume_lower, form_trigger=form_trigger, function_dev=function_dev, function_types=FUNCTIONS, input=input_dev, method=method, names_function=names_function, output=output, output_types=output_types(), pid=pid, sunrise_set_calc=sunrise_set_calc, table_conversion=Conversion, table_device_measurements=DeviceMeasurements, table_input=Input, table_output=Output, tags=tags, trigger=trigger, units=MEASUREMENTS, user=user) elif function_type == 'options': return render_template(function_page_options, and_=and_, action=action, actions_dict=actions_dict, camera=camera, choices_actions=choices_actions, choices_controller_ids=choices_controller_ids, choices_custom_functions=choices_custom_functions, choices_function=choices_function, choices_functions=choices_functions, choices_functions_add=choices_functions_add, choices_input=choices_input, choices_input_devices=choices_input_devices, choices_measurements_units=choices_measurements_units, choices_method=choices_method, choices_output=choices_output, choices_output_channels=choices_output_channels, choices_output_channels_measurements=choices_output_channels_measurements, choices_pid=choices_pid, choices_tag=choices_tag, conditional_conditions_list=CONDITIONAL_CONDITIONS, conditional=conditional, conditional_conditions=conditional_conditions, conditions_dict=conditions_dict, controllers=controllers, controller_type=controller_type, each_function=each_function, function=function, function_channel=function_channel, custom_commands=custom_commands, custom_options_values_actions=custom_options_values_actions, custom_options_values_controllers=custom_options_values_controllers, custom_options_values_function_channels=custom_options_values_function_channels, dict_actions=dict_actions, dict_controllers=dict_controllers, dict_measurements=dict_measurements, dict_outputs=dict_outputs, dict_units=dict_units, display_order_function=display_order_function, form_conditional=form_conditional, form_conditional_conditions=form_conditional_conditions, form_function=form_function, form_actions=form_actions, form_add_function=form_add_function, form_function_base=form_function_base, form_mod_pid_base=form_mod_pid_base, form_mod_pid_pwm_raise=form_mod_pid_pwm_raise, form_mod_pid_pwm_lower=form_mod_pid_pwm_lower, form_mod_pid_output_raise=form_mod_pid_output_raise, form_mod_pid_output_lower=form_mod_pid_output_lower, form_mod_pid_value_raise=form_mod_pid_value_raise, form_mod_pid_value_lower=form_mod_pid_value_lower, form_mod_pid_volume_raise=form_mod_pid_volume_raise, form_mod_pid_volume_lower=form_mod_pid_volume_lower, form_trigger=form_trigger, function_dev=function_dev, function_types=FUNCTIONS, input=input_dev, method=method, names_function=names_function, output=output, output_types=output_types(), pid=pid, sunrise_set_calc=sunrise_set_calc, table_conversion=Conversion, table_device_measurements=DeviceMeasurements, table_input=Input, table_output=Output, tags=tags, trigger=trigger, units=MEASUREMENTS, user=user) elif function_type == 'actions': return render_template('pages/actions.html', and_=and_, action=action, actions_dict=actions_dict, camera=camera, choices_actions=choices_actions, choices_controller_ids=choices_controller_ids, choices_custom_functions=choices_custom_functions, choices_function=choices_function, choices_functions=choices_functions, choices_functions_add=choices_functions_add, choices_input=choices_input, choices_input_devices=choices_input_devices, choices_measurements_units=choices_measurements_units, choices_method=choices_method, choices_output=choices_output, choices_output_channels=choices_output_channels, choices_output_channels_measurements=choices_output_channels_measurements, choices_pid=choices_pid, choices_tag=choices_tag, conditional_conditions_list=CONDITIONAL_CONDITIONS, conditional=conditional, conditional_conditions=conditional_conditions, conditions_dict=conditions_dict, controllers=controllers, controller_type=controller_type, each_action=each_action, each_function=each_function, function=function, function_channel=function_channel, custom_commands=custom_commands, custom_options_values_actions=custom_options_values_actions, custom_options_values_controllers=custom_options_values_controllers, custom_options_values_function_channels=custom_options_values_function_channels, dict_actions=dict_actions, dict_controllers=dict_controllers, dict_measurements=dict_measurements, dict_outputs=dict_outputs, dict_units=dict_units, display_order_function=display_order_function, form_conditional=form_conditional, form_conditional_conditions=form_conditional_conditions, form_function=form_function, form_actions=form_actions, form_add_function=form_add_function, form_function_base=form_function_base, form_mod_pid_base=form_mod_pid_base, form_mod_pid_pwm_raise=form_mod_pid_pwm_raise, form_mod_pid_pwm_lower=form_mod_pid_pwm_lower, form_mod_pid_output_raise=form_mod_pid_output_raise, form_mod_pid_output_lower=form_mod_pid_output_lower, form_mod_pid_value_raise=form_mod_pid_value_raise, form_mod_pid_value_lower=form_mod_pid_value_lower, form_mod_pid_volume_raise=form_mod_pid_volume_raise, form_mod_pid_volume_lower=form_mod_pid_volume_lower, form_trigger=form_trigger, function_dev=function_dev, function_types=FUNCTIONS, input=input_dev, method=method, names_function=names_function, output=output, output_types=output_types(), pid=pid, sunrise_set_calc=sunrise_set_calc, table_conversion=Conversion, table_device_measurements=DeviceMeasurements, table_input=Input, table_output=Output, tags=tags, trigger=trigger, units=MEASUREMENTS, user=user) elif function_type == 'conditions': return render_template('pages/function_options/conditional_condition.html', and_=and_, action=action, actions_dict=actions_dict, camera=camera, choices_controller_ids=choices_controller_ids, choices_custom_functions=choices_custom_functions, choices_function=choices_function, choices_functions=choices_functions, choices_functions_add=choices_functions_add, choices_input=choices_input, choices_input_devices=choices_input_devices, choices_measurements_units=choices_measurements_units, choices_method=choices_method, choices_output=choices_output, choices_output_channels=choices_output_channels, choices_output_channels_measurements=choices_output_channels_measurements, choices_pid=choices_pid, choices_tag=choices_tag, conditional_conditions_list=CONDITIONAL_CONDITIONS, conditional=conditional, conditional_conditions=conditional_conditions, conditions_dict=conditions_dict, controllers=controllers, controller_type=controller_type, each_condition=each_condition, each_function=each_function, function=function, function_channel=function_channel, custom_commands=custom_commands, custom_options_values_actions=custom_options_values_actions, custom_options_values_controllers=custom_options_values_controllers, custom_options_values_function_channels=custom_options_values_function_channels, dict_actions=dict_actions, dict_controllers=dict_controllers, dict_measurements=dict_measurements, dict_outputs=dict_outputs, dict_units=dict_units, display_order_function=display_order_function, form_conditional=form_conditional, form_conditional_conditions=form_conditional_conditions, form_function=form_function, form_actions=form_actions, form_add_function=form_add_function, form_function_base=form_function_base, form_mod_pid_base=form_mod_pid_base, form_mod_pid_pwm_raise=form_mod_pid_pwm_raise, form_mod_pid_pwm_lower=form_mod_pid_pwm_lower, form_mod_pid_output_raise=form_mod_pid_output_raise, form_mod_pid_output_lower=form_mod_pid_output_lower, form_mod_pid_value_raise=form_mod_pid_value_raise, form_mod_pid_value_lower=form_mod_pid_value_lower, form_mod_pid_volume_raise=form_mod_pid_volume_raise, form_mod_pid_volume_lower=form_mod_pid_volume_lower, form_trigger=form_trigger, function_dev=function_dev, function_types=FUNCTIONS, input=input_dev, method=method, names_function=names_function, output=output, output_types=output_types(), pid=pid, sunrise_set_calc=sunrise_set_calc, table_conversion=Conversion, table_device_measurements=DeviceMeasurements, table_input=Input, table_output=Output, tags=tags, trigger=trigger, units=MEASUREMENTS, user=user) else: return "Could not determine template"
def page_input(): """Display Data page options.""" input_type = request.args.get('input_type', None) input_id = request.args.get('input_id', None) action_id = request.args.get('action_id', None) each_input = None each_action = None if input_type in ['entry', 'options', 'actions']: each_input = Input.query.filter(Input.unique_id == input_id).first() if input_type == 'actions' and action_id: each_action = Actions.query.filter( Actions.unique_id == action_id).first() action = Actions.query.all() function = CustomController.query.all() input_dev = Input.query.all() input_channel = InputChannel.query.all() method = Method.query.all() measurement = Measurement.query.all() output = Output.query.all() output_channel = OutputChannel.query.all() pid = PID.query.all() user = User.query.all() unit = Unit.query.all() display_order_input = csv_to_list_of_str(DisplayOrder.query.first().inputs) form_add_input = forms_input.InputAdd() form_mod_input = forms_input.InputMod() form_actions = forms_action.Actions() dict_inputs = parse_input_information() dict_actions = parse_action_information() custom_options_values_inputs = parse_custom_option_values( input_dev, dict_controller=dict_inputs) custom_options_values_input_channels = parse_custom_option_values_input_channels_json( input_channel, dict_controller=dict_inputs, key_name='custom_channel_options') custom_options_values_actions = {} for each_action_dev in action: try: custom_options_values_actions[each_action_dev.unique_id] = json.loads(each_action_dev.custom_options) except: custom_options_values_actions[each_action_dev.unique_id] = {} custom_commands = {} for each_input_dev in input_dev: if each_input_dev.device in dict_inputs and 'custom_commands' in dict_inputs[each_input_dev.device]: custom_commands[each_input_dev.device] = True # Generate dict that incorporate user-added measurements/units dict_outputs = parse_output_information() dict_units = add_custom_units(unit) dict_measurements = add_custom_measurements(measurement) # Generate Action dropdown for use with Inputs choices_actions = [] list_actions_sorted = generate_form_action_list(dict_actions, application=["inputs"]) for name in list_actions_sorted: choices_actions.append((name, dict_actions[name]['name'])) # Create list of choices to be used in dropdown menus choices_function = utils_general.choices_functions( function, dict_units, dict_measurements) choices_input = utils_general.choices_inputs( input_dev, dict_units, dict_measurements) choices_method = utils_general.choices_methods(method) choices_output = utils_general.choices_outputs( output, OutputChannel, dict_outputs, dict_units, dict_measurements) choices_output_channels = utils_general.choices_outputs_channels( output, output_channel, dict_outputs) choices_output_channels_measurements = utils_general.choices_outputs_channels_measurements( output, OutputChannel, dict_outputs, dict_units, dict_measurements) choices_pid = utils_general.choices_pids( pid, dict_units, dict_measurements) choices_pid_devices = utils_general.choices_pids_devices(pid) choices_unit = utils_general.choices_units(unit) choices_measurement = utils_general.choices_measurements(measurement) choices_measurements_units = utils_general.choices_measurements_units(measurement, unit) # Create dict of Input names names_input = {} all_elements = input_dev for each_element in all_elements: names_input[each_element.unique_id] = '[{id:02d}] ({uid}) {name}'.format( id=each_element.id, uid=each_element.unique_id.split('-')[0], name=each_element.name) # Create list of file names from the input_options directory # Used in generating the correct options for each input controller input_templates = [] input_path = os.path.join( INSTALL_DIRECTORY, 'mycodo/mycodo_flask/templates/pages/data_options/input_options') for (_, _, file_names) in os.walk(input_path): input_templates.extend(file_names) break # Compile a list of 1-wire devices devices_1wire = [] if os.path.isdir(PATH_1WIRE): for each_name in os.listdir(PATH_1WIRE): if 'bus' not in each_name and '-' in each_name: devices_1wire.append( {'name': each_name, 'value': each_name.split('-')[1]} ) # Compile a list of 1-wire devices (using ow-shell) devices_1wire_ow_shell = [] if not Input.query.filter(Input.device == "DS18B20_OWS").count(): pass elif current_app.config['TESTING']: logger.debug("Testing: Skipping testing for 'ow-shell'") elif not dpkg_package_exists('ow-shell'): logger.debug("Package 'ow-shell' not found") else: logger.debug("Package 'ow-shell' found") try: test_cmd = subprocess.check_output(['owdir']).splitlines() for each_ow in test_cmd: str_ow = re.sub("\ |\/|\'", "", each_ow.decode("utf-8")) # Strip / and ' if '.' in str_ow and len(str_ow) == 15: devices_1wire_ow_shell.append(str_ow) except Exception: logger.error("Error finding 1-wire devices with 'owdir'") # Find FTDI devices ftdi_devices = [] if not current_app.config['TESTING']: for each_input_dev in input_dev: if each_input_dev.interface == "FTDI": from mycodo.devices.atlas_scientific_ftdi import get_ftdi_device_list ftdi_devices = get_ftdi_device_list() break if not input_type: return render_template('pages/input.html', and_=and_, action=action, choices_actions=choices_actions, choices_function=choices_function, choices_input=choices_input, choices_output=choices_output, choices_measurement=choices_measurement, choices_measurements_units=choices_measurements_units, choices_method=choices_method, choices_output_channels=choices_output_channels, choices_output_channels_measurements=choices_output_channels_measurements, choices_pid=choices_pid, choices_pid_devices=choices_pid_devices, choices_unit=choices_unit, custom_commands=custom_commands, custom_options_values_actions=custom_options_values_actions, custom_options_values_inputs=custom_options_values_inputs, custom_options_values_input_channels=custom_options_values_input_channels, dict_actions=dict_actions, dict_inputs=dict_inputs, dict_measurements=dict_measurements, dict_units=dict_units, display_order_input=display_order_input, form_actions=form_actions, form_add_input=form_add_input, form_mod_input=form_mod_input, ftdi_devices=ftdi_devices, input_channel=input_channel, input_templates=input_templates, names_input=names_input, output=output, output_types=output_types(), pid=pid, table_conversion=Conversion, table_device_measurements=DeviceMeasurements, table_input=Input, user=user, devices_1wire_ow_shell=devices_1wire_ow_shell, devices_1wire=devices_1wire) elif input_type == 'entry': return render_template('pages/data_options/input_entry.html', and_=and_, action=action, choices_actions=choices_actions, choices_function=choices_function, choices_input=choices_input, choices_output=choices_output, choices_measurement=choices_measurement, choices_measurements_units=choices_measurements_units, choices_method=choices_method, choices_output_channels=choices_output_channels, choices_output_channels_measurements=choices_output_channels_measurements, choices_pid=choices_pid, choices_pid_devices=choices_pid_devices, choices_unit=choices_unit, custom_commands=custom_commands, custom_options_values_actions=custom_options_values_actions, custom_options_values_inputs=custom_options_values_inputs, custom_options_values_input_channels=custom_options_values_input_channels, dict_actions=dict_actions, dict_inputs=dict_inputs, dict_measurements=dict_measurements, dict_units=dict_units, display_order_input=display_order_input, each_input=each_input, form_actions=form_actions, form_add_input=form_add_input, form_mod_input=form_mod_input, ftdi_devices=ftdi_devices, input_channel=input_channel, input_templates=input_templates, names_input=names_input, output=output, output_types=output_types(), pid=pid, table_conversion=Conversion, table_device_measurements=DeviceMeasurements, table_input=Input, user=user, devices_1wire_ow_shell=devices_1wire_ow_shell, devices_1wire=devices_1wire) elif input_type == 'options': return render_template('pages/data_options/input_options.html', and_=and_, action=action, choices_actions=choices_actions, choices_function=choices_function, choices_input=choices_input, choices_output=choices_output, choices_measurement=choices_measurement, choices_measurements_units=choices_measurements_units, choices_method=choices_method, choices_output_channels=choices_output_channels, choices_output_channels_measurements=choices_output_channels_measurements, choices_pid=choices_pid, choices_pid_devices=choices_pid_devices, choices_unit=choices_unit, custom_commands=custom_commands, custom_options_values_actions=custom_options_values_actions, custom_options_values_inputs=custom_options_values_inputs, custom_options_values_input_channels=custom_options_values_input_channels, dict_actions=dict_actions, dict_inputs=dict_inputs, dict_measurements=dict_measurements, dict_units=dict_units, display_order_input=display_order_input, each_input=each_input, form_actions=form_actions, form_add_input=form_add_input, form_mod_input=form_mod_input, ftdi_devices=ftdi_devices, input_channel=input_channel, input_templates=input_templates, names_input=names_input, output=output, output_types=output_types(), pid=pid, table_conversion=Conversion, table_device_measurements=DeviceMeasurements, table_input=Input, user=user, devices_1wire_ow_shell=devices_1wire_ow_shell, devices_1wire=devices_1wire) elif input_type == 'actions': return render_template('pages/actions.html', and_=and_, action=action, choices_actions=choices_actions, choices_function=choices_function, choices_input=choices_input, choices_output=choices_output, choices_measurement=choices_measurement, choices_measurements_units=choices_measurements_units, choices_method=choices_method, choices_output_channels=choices_output_channels, choices_output_channels_measurements=choices_output_channels_measurements, choices_pid=choices_pid, choices_pid_devices=choices_pid_devices, choices_unit=choices_unit, custom_commands=custom_commands, custom_options_values_actions=custom_options_values_actions, custom_options_values_inputs=custom_options_values_inputs, custom_options_values_input_channels=custom_options_values_input_channels, dict_actions=dict_actions, dict_inputs=dict_inputs, dict_measurements=dict_measurements, dict_units=dict_units, display_order_input=display_order_input, each_action=each_action, each_input=each_input, form_actions=form_actions, form_add_input=form_add_input, form_mod_input=form_mod_input, ftdi_devices=ftdi_devices, input_channel=input_channel, input_templates=input_templates, names_input=names_input, output=output, output_types=output_types(), pid=pid, table_conversion=Conversion, table_device_measurements=DeviceMeasurements, table_input=Input, user=user, devices_1wire_ow_shell=devices_1wire_ow_shell, devices_1wire=devices_1wire)
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 = f"{timestamp}\n[Trigger {self.unique_id} ({self.trigger_name})]" trigger = db_retrieve_table_daemon(Trigger, unique_id=self.unique_id, entry='first') device_id = trigger.measurement.split(',')[0] device = None input_dev = db_retrieve_table_daemon(Input, unique_id=device_id, entry='first') if input_dev: device = input_dev function = db_retrieve_table_daemon(CustomController, unique_id=device_id, entry='first') if function: device = CustomController 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, Function, 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: import RPi.GPIO as GPIO GPIO.setmode(GPIO.BCM) GPIO.setup(int(input_dev.pin), GPIO.IN) gpio_state = GPIO.input(int(input_dev.pin)) except Exception as e: gpio_state = None self.logger.error(f"Exception reading the GPIO pin: {e}") if (gpio_state is not None and gpio_state == trigger.if_sensor_gpio_state): message += f" GPIO State Detected (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 = suntime_calculate_next_sunrise_sunset_epoch( trigger.latitude, trigger.longitude, trigger.date_offset_days, trigger.time_offset_minutes, trigger.rise_or_set) # 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 actions = parse_action_information() trigger_controller_actions(actions, self.unique_id, message=message, debug=self.log_level_debug)
from mycodo.config import INSTALL_DIRECTORY from mycodo.scripts.generate_doc_output import generate_controller_doc from mycodo.utils.actions import parse_action_information save_path = os.path.join(INSTALL_DIRECTORY, "docs/Supported-Actions.md") actions_info = OrderedDict() mycodo_info = OrderedDict() def repeat_to_length(s, wanted): return (s * (wanted // len(s) + 1))[:wanted] if __name__ == "__main__": for action_id, action_data in parse_action_information( exclude_custom=True).items(): name_str = "" if 'manufacturer' in action_data and action_data['manufacturer']: name_str += f"{action_data['manufacturer']}" if 'name' in action_data and action_data['name']: name_str += f": {action_data['name']}" if 'library' in action_data and action_data['library']: name_str += f": {action_data['library']}" if ('manufacturer' in action_data and action_data['manufacturer'] in ['Linux', 'Mycodo', 'Raspberry Pi', 'System']): if name_str in mycodo_info and 'dependencies_module' in mycodo_info[ name_str]: # Multiple sets of dependencies, append library mycodo_info[name_str]['dependencies_module'].append(
def action_add(form): """Add an Action.""" messages = { "success": [], "info": [], "warning": [], "error": [] } action_id = None list_unmet_deps = [] dep_name = "" page_refresh = False if not current_app.config['TESTING']: dep_unmet, _, dep_message = return_dependencies(form.action_type.data) if dep_unmet: for each_dep in dep_unmet: list_unmet_deps.append(each_dep[3]) messages["error"].append( f"{form.action_type.data} has unmet dependencies. " "They must be installed before the Action can be added.") dep_name = form.action_type.data return messages, dep_name, list_unmet_deps, dep_message, None dict_actions = parse_action_information() controller_type, controller_table, _ = which_controller(form.device_id.data) if controller_type not in ['Conditional', 'Trigger', 'Function', 'Input']: messages["error"].append(f"Invalid controller type: {controller_type}") if controller_type: controller = controller_table.query.filter( controller_table.unique_id == form.device_id.data).first() try: if controller and controller.is_activated: messages["error"].append("Deactivate controller before adding an Action") except: pass # is_activated doesn't exist if form.action_type.data == '': messages["error"].append("Must select an action") try: new_action = Actions() new_action.function_id = form.device_id.data new_action.function_type = form.function_type.data new_action.action_type = form.action_type.data # # Custom Options # # Generate string to save from custom options messages["error"], custom_options = custom_options_return_json( messages["error"], dict_actions, device=form.action_type.data, use_defaults=True) new_action.custom_options = custom_options if not messages["error"]: new_action.save() action_id = new_action.unique_id page_refresh = True messages["success"].append(f"{TRANSLATIONS['add']['title']} {TRANSLATIONS['actions']['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: messages["error"].append(str(except_msg)) return messages, dep_name, list_unmet_deps, action_id, page_refresh
def admin_dependencies(device): """Display Dependency page""" form_dependencies = forms_dependencies.Dependencies() if device != '0': # Only loading a single dependency page device_unmet_dependencies, _, _ = utils_general.return_dependencies( device) elif form_dependencies.device.data: device_unmet_dependencies, _, _ = utils_general.return_dependencies( form_dependencies.device.data) else: device_unmet_dependencies = [] unmet_dependencies = OrderedDict() unmet_exist = False met_dependencies = [] met_exist = False unmet_list = {} install_in_progress = False device_name = None dependencies_message = "" # Read from the dependency status file created by the upgrade script # to indicate if the upgrade is running. try: with open(DEPENDENCY_INIT_FILE) as f: dep = int(f.read(1)) except (IOError, ValueError): try: with open(DEPENDENCY_INIT_FILE, 'w') as f: f.write('0') finally: dep = 0 if dep: install_in_progress = True list_dependencies = [ parse_function_information(), parse_action_information(), parse_input_information(), parse_output_information(), parse_widget_information(), CAMERA_INFO, FUNCTION_INFO, METHOD_INFO, DEPENDENCIES_GENERAL ] for each_section in list_dependencies: for each_device in each_section: if device in each_section: # Determine if a message for the dependencies exists if "dependencies_message" in each_section[device]: dependencies_message = each_section[device][ "dependencies_message"] # Find friendly name for device for each_device_, each_val in each_section[device].items(): if each_device_ in [ 'name', 'input_name', 'output_name', 'function_name', 'widget_name' ]: device_name = each_val break # Only get all dependencies when not loading a single dependency page if device == '0': # Determine if there are any unmet dependencies for every device dep_unmet, dep_met, _ = utils_general.return_dependencies( each_device) unmet_dependencies.update({each_device: dep_unmet}) if dep_unmet: unmet_exist = True # Determine if there are any met dependencies if dep_met: if each_device not in met_dependencies: met_dependencies.append(each_device) met_exist = True # Find all the devices that use each unmet dependency if unmet_dependencies[each_device]: for each_dep in unmet_dependencies[each_device]: # Determine if the third element of the tuple is a list, convert it to a tuple if (type(each_dep) == tuple and len(each_dep) == 3 and type(each_dep[2]) == list): each_dep = list(each_dep) each_dep[2] = tuple(each_dep[2]) each_dep = tuple(each_dep) if each_dep not in unmet_list: unmet_list[each_dep] = [] if each_device not in unmet_list[each_dep]: unmet_list[each_dep].append(each_device) if request.method == 'POST': if not utils_general.user_has_permission('edit_controllers'): return redirect( url_for('routes_admin.admin_dependencies', device=device)) if form_dependencies.install.data: with open(DEPENDENCY_INIT_FILE, 'w') as f: f.write('1') install_deps = threading.Thread(target=install_dependencies, args=(device_unmet_dependencies, )) install_deps.start() return redirect( url_for('routes_admin.admin_dependencies', device=device)) return render_template('admin/dependencies.html', measurements=parse_input_information(), unmet_list=unmet_list, dependencies_message=dependencies_message, device=device, device_name=device_name, install_in_progress=install_in_progress, unmet_dependencies=unmet_dependencies, unmet_exist=unmet_exist, met_dependencies=met_dependencies, met_exist=met_exist, form_dependencies=form_dependencies, device_unmet_dependencies=device_unmet_dependencies)