def all_outputs_initialize(self, outputs): """ Initialize all output variables and classes """ self.dict_outputs = parse_output_information() self.output_types = output_types() for each_output in outputs: try: self.output_type[each_output.unique_id] = each_output.output_type self.output_unique_id[each_output.unique_id] = {} if 'channels_dict' in self.dict_outputs[each_output.output_type]: for each_channel in self.dict_outputs[each_output.output_type]['channels_dict']: self.output_unique_id[each_output.unique_id][each_channel] = None else: self.output_unique_id[each_output.unique_id][0] = None if each_output.output_type in self.dict_outputs: output_loaded = load_module_from_file( self.dict_outputs[each_output.output_type]['file_path'], 'outputs') self.output[each_output.unique_id] = output_loaded.OutputModule(each_output) self.output[each_output.unique_id].setup_output() self.output[each_output.unique_id].init_post() self.logger.debug("{id} ({name}) Initialized".format( id=each_output.unique_id.split('-')[0], name=each_output.name)) except: self.logger.exception("Could not initialize output {}".format( each_output.unique_id))
def get_installed_dependencies(): met_deps = [] list_dependencies = [ parse_function_information(), parse_input_information(), parse_output_information(), CAMERA_INFO, FUNCTION_ACTION_INFO, FUNCTION_INFO, LCD_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: entry = '{0} {1}'.format(install_type, install_id) if install_type in ['pip-pypi', 'pip-git']: try: module = importlib.util.find_spec(package) if module is not None and entry not in met_deps: met_deps.append(entry) except Exception: logger.error( 'Exception checking python dependency: ' '{dep}'.format(dep=package)) elif 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 entry not in met_deps: met_deps.append(entry) return met_deps
class OutputAdd(FlaskForm): choices_outputs = [] dict_outputs = parse_output_information() list_outputs_sorted = generate_form_output_list(dict_outputs) for each_output in list_outputs_sorted: value = '{inp},'.format(inp=each_output) name = '{name}'.format(name=dict_outputs[each_output]['output_name']) if 'output_library' in dict_outputs[each_output]: name += ' ({lib})'.format( lib=dict_outputs[each_output]['output_library']) if ('interfaces' in dict_outputs[each_output] and dict_outputs[each_output]['interfaces']): for each_interface in dict_outputs[each_output]['interfaces']: tmp_value = '{val}{int}'.format(val=value, int=each_interface) tmp_name = '{name} [{int}]'.format(name=name, int=each_interface) choices_outputs.append((tmp_value, tmp_name)) else: choices_outputs.append((value, name)) choices_outputs = sort_tuple(choices_outputs) output_type = SelectField(choices=choices_outputs, validators=[DataRequired()]) output_quantity = IntegerField(lazy_gettext('Quantity')) output_add = SubmitField(TRANSLATIONS['add']['title'])
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 test_add_all_output_devices_logged_in_as_admin(_, testapp): """ Verifies adding all outputs as a logged in admin user """ print("\nTest: test_add_all_output_devices_logged_in_as_admin") login_user(testapp, 'admin', '53CR3t_p4zZW0rD') # Add All Inputs output_count = 0 dict_outputs = parse_output_information() list_outputs_sorted = generate_form_output_list(dict_outputs) choices_output = [] for each_output in list_outputs_sorted: if 'interfaces' not in dict_outputs[each_output]: choices_output.append('{inp},'.format(inp=each_output)) else: for each_interface in dict_outputs[each_output]['interfaces']: choices_output.append('{inp},{int}'.format(inp=each_output, int=each_interface)) for index, each_output in enumerate(choices_output): print("test_add_all_output_devices_logged_in_as_admin: Adding, saving, and deleting Output ({}/{}): {}".format( index + 1, len(choices_output), each_output)) response = add_output(testapp, output_type=each_output) 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 # Verify data was entered into the database output_count += 1 assert Output.query.count() == output_count, "Number of Outputs doesn't match: In DB {}, Should be: {}".format( Output.query.count(), output_count) output = Output.query.filter(Output.id == output_count).first() # Save output response = save_data(testapp, 'output', device_dev=output) 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 # Delete output (speeds up further output addition checking) response = delete_data(testapp, 'output', device_dev=output) 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 output_count -= 1 assert Output.query.count() == output_count, "Number of Outputs doesn't match: In DB {}, Should be: {}".format( Output.query.count(), output_count)
def page_output_submit(): """Submit form for Output page""" messages = {"success": [], "info": [], "warning": [], "error": []} page_refresh = False output_id = None dep_unmet = '' dep_name = '' dep_list = [] dep_message = '' size_y = None form_add_output = forms_output.OutputAdd() form_mod_output = forms_output.OutputMod() if not utils_general.user_has_permission('edit_controllers'): messages["error"].append("Your permissions do not allow this action") if not messages["error"]: if form_add_output.output_add.data: (messages, dep_name, dep_list, dep_message, output_id, size_y) = utils_output.output_add(form_add_output, request.form) if dep_list: dep_unmet = form_add_output.output_type.data.split(',')[0] elif form_mod_output.output_mod.data: messages, page_refresh = utils_output.output_mod( form_mod_output, request.form) output_id = form_mod_output.output_id.data elif form_mod_output.output_delete.data: messages = utils_output.output_del(form_mod_output) output_id = form_mod_output.output_id.data # Custom action else: custom_button = False for key in request.form.keys(): if key.startswith('custom_button_'): custom_button = True break if custom_button: messages = utils_general.custom_command( "Output", parse_output_information(), form_mod_output.output_id.data, request.form) else: messages["error"].append("Unknown output directive") return jsonify( data={ 'output_id': output_id, 'dep_name': dep_name, 'dep_list': dep_list, 'dep_unmet': dep_unmet, 'dep_message': dep_message, 'size_y': size_y, 'messages': messages, "page_refresh": page_refresh })
def add_mod_output(self, output_id): """ Add or modify local dictionary of output settings form SQL database When a output is added or modified while the output controller is running, these local variables need to also be modified to maintain consistency between the SQL database and running controller. :param output_id: Unique ID for each output :type output_id: str :return: 0 for success, 1 for fail, with success for fail message :rtype: int, str """ try: self.dict_outputs = parse_output_information() output = db_retrieve_table_daemon(Output, unique_id=output_id) self.output_type[output_id] = output.output_type self.output_unique_id[output_id] = {} if 'channels_dict' in self.dict_outputs[output.output_type]: for each_channel in self.dict_outputs[ output.output_type]['channels_dict']: self.output_unique_id[output_id][each_channel] = None else: self.output_unique_id[output_id][0] = None if self.output_type[output_id] in self.dict_outputs: if ('no_run' in self.dict_outputs[output.output_type] and self.dict_outputs[output.output_type]['no_run']): pass else: # Try to stop the output if output_id in self.output: try: self.output[output_id].stop_output() except Exception: self.logger.exception("Stopping output") output_loaded, status = load_module_from_file( self.dict_outputs[self.output_type[output_id]] ['file_path'], 'outputs') if output_loaded: self.output[output_id] = output_loaded.OutputModule( output) self.output[output_id].try_initialize() self.output[output_id].init_post() return 0, "add_mod_output() Success" except Exception as e: return 1, f"add_mod_output() Error: {output_id}: {e}"
def all_outputs_initialize(self, outputs): """ Initialize all output variables and classes """ self.dict_outputs = parse_output_information() self.output_types = output_types() for each_output in outputs: try: self.output_unique_id[ each_output.unique_id] = each_output.unique_id self.output_type[ each_output.unique_id] = each_output.output_type self.output_name[each_output.unique_id] = each_output.name self.output_amps[each_output.unique_id] = each_output.amps self.output_state_startup[ each_output.unique_id] = each_output.state_startup self.output_startup_value[ each_output.unique_id] = each_output.startup_value self.output_state_shutdown[ each_output.unique_id] = each_output.state_shutdown self.output_shutdown_value[ each_output.unique_id] = each_output.shutdown_value self.output_on_until[ each_output.unique_id] = datetime.datetime.now() self.output_last_duration[each_output.unique_id] = 0 self.output_on_duration[each_output.unique_id] = False self.output_off_triggered[each_output.unique_id] = False self.output_time_turned_on[each_output.unique_id] = None self.output_force_command[ each_output.unique_id] = each_output.force_command self.trigger_functions_at_start[ each_output. unique_id] = each_output.trigger_functions_at_start if each_output.output_type in self.dict_outputs: output_loaded = load_module_from_file( self.dict_outputs[each_output.output_type] ['file_path'], 'outputs') self.output[ each_output.unique_id] = output_loaded.OutputModule( each_output) self.output[each_output.unique_id].setup_output() self.output[each_output.unique_id].init_post() self.logger.debug("{id} ({name}) Initialized".format( id=each_output.unique_id.split('-')[0], name=each_output.name)) except: self.logger.exception("Could not initialize output {}".format( each_output.unique_id))
def all_outputs_initialize(self, outputs): """Initialize all output variables and classes.""" self.dict_outputs = parse_output_information() self.output_types = output_types() for each_output in outputs: if each_output.output_type not in self.dict_outputs: self.logger.error( f"'{each_output.output_type}' not found in Output dictionary. Not starting Output." ) continue try: self.output_type[ each_output.unique_id] = each_output.output_type self.output_unique_id[each_output.unique_id] = {} if 'channels_dict' in self.dict_outputs[ each_output.output_type]: for each_channel in self.dict_outputs[ each_output.output_type]['channels_dict']: self.output_unique_id[ each_output.unique_id][each_channel] = None else: self.output_unique_id[each_output.unique_id][0] = None if each_output.output_type in self.dict_outputs: if ('no_run' in self.dict_outputs[each_output.output_type] and self.dict_outputs[ each_output.output_type]['no_run']): continue output_loaded, status = load_module_from_file( self.dict_outputs[each_output.output_type] ['file_path'], 'outputs') if output_loaded: self.output[each_output. unique_id] = output_loaded.OutputModule( each_output) self.output[each_output.unique_id].try_initialize() self.output[each_output.unique_id].init_post() self.logger.debug( f"{each_output.unique_id.split('-')[0]} ({each_output.name}) Initialized" ) except: self.logger.exception( f"Could not initialize output {each_output.unique_id}")
def add_mod_output(self, output_id): """ Add or modify local dictionary of output settings form SQL database When a output is added or modified while the output controller is running, these local variables need to also be modified to maintain consistency between the SQL database and running controller. :param output_id: Unique ID for each output :type output_id: str :return: 0 for success, 1 for fail, with success for fail message :rtype: int, str """ try: self.dict_outputs = parse_output_information() output = db_retrieve_table_daemon(Output, unique_id=output_id) self.output_unique_id[output_id] = output.unique_id self.output_type[output_id] = output.output_type self.output_name[output_id] = output.name self.output_amps[output_id] = output.amps self.output_state_startup[output_id] = output.state_startup self.output_startup_value[output_id] = output.startup_value self.output_state_shutdown[output_id] = output.state_shutdown self.output_shutdown_value[output_id] = output.shutdown_value self.output_on_until[output_id] = datetime.datetime.now() self.output_time_turned_on[output_id] = None self.output_last_duration[output_id] = 0 self.output_on_duration[output_id] = False self.output_off_triggered[output_id] = False self.output_force_command[output_id] = output.force_command self.trigger_functions_at_start[ output_id] = output.trigger_functions_at_start if self.output_type[output_id] in self.dict_outputs: output_loaded = load_module_from_file( self.dict_outputs[self.output_type[output_id]] ['file_path'], 'outputs') self.output[output_id] = output_loaded.OutputModule(output) self.output[output_id].setup_output() self.output[output_id].init_post() return 0, "add_mod_output() Success" except Exception as e: return 1, "add_mod_output() Error: {id}: {e}".format(id=output_id, e=e)
def del_output(self, output_id): """ Delete output from being managed by Output controller :param output_id: Unique ID for output :type output_id: str :return: 0 for success, 1 for fail (with error message) :rtype: int, str """ try: self.dict_outputs = parse_output_information() if ('no_run' in self.dict_outputs[self.output_type[output_id]] and self.dict_outputs[self.output_type[output_id]]['no_run']): pass elif output_id not in self.output_type: msg = "Output ID not found. Can't delete nonexistent Output." self.logger.error(msg) return 1, msg # instruct output to shutdown shutdown_timer = timeit.default_timer() if ('no_run' in self.dict_outputs[self.output_type[output_id]] and self.dict_outputs[self.output_type[output_id]]['no_run']): pass else: try: self.output[output_id].shutdown(shutdown_timer) except Exception as err: self.logger.error( f"Could not shut down output gracefully: {err}") self.output_unique_id.pop(output_id, None) self.output_type.pop(output_id, None) self.output.pop(output_id, None) msg = f"Output {output_id} Deleted." self.logger.debug(msg) return 0, msg except Exception as e: self.logger.exception(1) return 1, f"Error deleting Output {output_id}: {e}"
def get(self): """Show form choices for all output measurements.""" if not utils_general.user_has_permission('view_settings'): abort(403) try: output = Output.query.all() dict_outputs = parse_output_information() dict_measurements = add_custom_measurements( Measurement.query.all()) dict_units = add_custom_units(Unit.query.all()) output_choices = utils_general.choices_outputs( output, OutputChannel, dict_outputs, dict_units, dict_measurements) if output_choices: return {'choices outputs measurements': output_choices}, 200 except Exception: abort(500, message='An exception occurred', error=traceback.format_exc())
def test_add_all_output_devices_logged_in_as_admin(_, testapp): """ Verifies adding all outputs as a logged in admin user """ print("\nTest: test_add_all_output_devices_logged_in_as_admin") login_user(testapp, 'admin', '53CR3t_p4zZW0rD') # Add All Inputs output_count = 0 dict_outputs = parse_output_information() list_outputs_sorted = generate_form_output_list(dict_outputs) choices_output = [] for each_output in list_outputs_sorted: if 'interfaces' not in dict_outputs[each_output]: choices_output.append('{inp},'.format(inp=each_output)) else: for each_interface in dict_outputs[each_output]['interfaces']: choices_output.append('{inp},{int}'.format(inp=each_output, int=each_interface)) for index, each_output in enumerate(choices_output): print( "test_add_all_data_devices_logged_in_as_admin: Adding and deleting Output ({}/{}): {}" .format(index + 1, len(choices_output), each_output)) response = add_output(testapp, output_type=each_output) # Verify success message flashed assert "with ID 1 successfully added" in response # Verify data was entered into the database output_count += 1 assert Output.query.count( ) == output_count, "Number of Outputs doesn't match: In DB {}, Should be: {}".format( Output.query.count(), output_count) # Delete output (speeds up further output addition checking) output = Output.query.filter(Output.id == output_count).first() response = delete_data(testapp, data_type='output', device_dev=output) assert "Success: Delete output with ID: {}".format( output.unique_id) in response output_count -= 1
def get_installed_dependencies(): met_deps = [] list_dependencies = [ parse_controller_information(), parse_input_information(), parse_output_information(), CALIBRATION_INFO, CAMERA_INFO, FUNCTION_ACTION_INFO, FUNCTION_INFO, LCD_INFO, MATH_INFO, METHOD_INFO, ] 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: entry = '{0} {1}'.format(install_type, install_id) if install_type in ['pip-pypi', 'pip-git']: try: module = importlib.util.find_spec(package) if module is not None and entry not in met_deps: met_deps.append(entry) except Exception: logger.error( 'Exception checking python dependency: ' '{dep}'.format(dep=package)) elif install_type == 'apt': cmd = 'dpkg -l {}'.format(package) _, _, status = cmd_output(cmd, user='******') if not status and entry not in met_deps: met_deps.append(entry) return met_deps
def output_add(form_add, request_form): action = '{action} {controller}'.format( action=TRANSLATIONS['add']['title'], controller=TRANSLATIONS['output']['title']) error = [] dict_outputs = parse_output_information() if current_app.config['TESTING']: dep_unmet = False else: dep_unmet, _ = return_dependencies(form_add.output_type.data.split(',')[0]) 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=form_add.output_type.data.split(',')[0], dep=', '.join(list_unmet_deps))) if not is_int(form_add.output_quantity.data, check_range=[1, 20]): error.append("{error}. {accepted_values}: 1-20".format( error=gettext("Invalid quantity"), accepted_values=gettext("Acceptable values") )) if form_add.output_type.data.count(',') == 1: output_type = form_add.output_type.data.split(',')[0] output_interface = form_add.output_type.data.split(',')[1] else: output_type = '' output_interface = '' error.append("Invalid output string (must be a comma-separated string)") if not error: for _ in range(0, form_add.output_quantity.data): try: new_output = Output() try: from RPi import GPIO if GPIO.RPI_INFO['P1_REVISION'] == 1: new_output.i2c_bus = 0 else: new_output.i2c_bus = 1 except: logger.error( "RPi.GPIO and Raspberry Pi required for this action") new_output.name = "Name" new_output.output_type = output_type new_output.interface = output_interface # # Set default values for new input being added # # input add options if output_type in dict_outputs: def dict_has_value(key): if (key in dict_outputs[output_type] and dict_outputs[output_type][key] is not None): return True # # Interfacing options # if output_interface == 'I2C': if dict_has_value('i2c_address_default'): new_output.i2c_location = dict_outputs[output_type]['i2c_address_default'] elif dict_has_value('i2c_location'): new_output.i2c_location = dict_outputs[output_type]['i2c_location'][0] # First list entry if output_interface == 'FTDI': if dict_has_value('ftdi_location'): new_output.ftdi_location = dict_outputs[output_type]['ftdi_location'] if output_interface == 'UART': if dict_has_value('uart_location'): new_output.uart_location = dict_outputs[output_type]['uart_location'] # UART options if dict_has_value('uart_baud_rate'): new_output.baud_rate = dict_outputs[output_type]['uart_baud_rate'] if dict_has_value('pin_cs'): new_output.pin_cs = dict_outputs[output_type]['pin_cs'] if dict_has_value('pin_miso'): new_output.pin_miso = dict_outputs[output_type]['pin_miso'] if dict_has_value('pin_mosi'): new_output.pin_mosi = dict_outputs[output_type]['pin_mosi'] if dict_has_value('pin_clock'): new_output.pin_clock = dict_outputs[output_type]['pin_clock'] # Bluetooth (BT) options elif output_interface == 'BT': if dict_has_value('bt_location'): new_output.location = dict_outputs[output_type]['bt_location'] if dict_has_value('bt_adapter'): new_output.bt_adapter = dict_outputs[output_type]['bt_adapter'] # GPIO options elif output_interface == 'GPIO': if dict_has_value('gpio_pin'): new_output.pin = dict_outputs[output_type]['gpio_pin'] # Custom location location elif dict_has_value('location'): new_output.location = dict_outputs[output_type]['location']['options'][0][0] # First entry in list # Generate string to save from custom options error, custom_options = custom_options_return_json( error, dict_outputs, request_form, device=output_type, use_defaults=True) new_output.custom_options = custom_options # # Execute at Creation # new_output.unique_id = set_uuid() if 'execute_at_creation' in dict_outputs[output_type] and not current_app.config['TESTING']: dict_outputs[output_type]['execute_at_creation']( new_output, dict_outputs[output_type]) if not error: new_output.save() display_order = csv_to_list_of_str( DisplayOrder.query.first().output) DisplayOrder.query.first().output = add_display_order( display_order, new_output.unique_id) db.session.commit() # # If measurements defined in the Output Module # if ('measurements_dict' in dict_outputs[output_type] and dict_outputs[output_type]['measurements_dict'] != []): for each_measurement in dict_outputs[output_type]['measurements_dict']: measure_info = dict_outputs[output_type]['measurements_dict'][each_measurement] new_measurement = DeviceMeasurements() if 'name' in measure_info: new_measurement.name = measure_info['name'] new_measurement.device_id = new_output.unique_id new_measurement.measurement = measure_info['measurement'] new_measurement.unit = measure_info['unit'] new_measurement.channel = each_measurement new_measurement.save() for each_channel, channel_info in dict_outputs[output_type]['channels_dict'].items(): new_channel = OutputChannel() new_channel.channel = each_channel new_channel.output_id = new_output.unique_id # Generate string to save from custom options error, custom_options = custom_channel_options_return_json( error, dict_outputs, request_form, new_output.unique_id, each_channel, device=output_type, use_defaults=True) new_channel.custom_options = custom_options new_channel.save() # Refresh output settings if not current_app.config['TESTING']: manipulate_output('Add', new_output.unique_id) flash(gettext("{dev} with ID %(id)s successfully added".format( dev=dict_outputs[output_type]['output_name']), id=new_output.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: logger.exception(1) return dep_unmet
msg = "ERROR: post-alembic revision {}: {}".format( each_revision, traceback.format_exc()) error.append(msg) print(msg) elif each_revision == 'af5891792291': # Set the output_type for PID controller outputs print("Executing post-alembic code for revision {}".format( each_revision)) try: from mycodo.utils.outputs import parse_output_information from mycodo.databases.models import DeviceMeasurements from mycodo.databases.models import Output from mycodo.databases.models import PID dict_outputs = parse_output_information() with session_scope(MYCODO_DB_PATH) as session: for each_pid in session.query(PID).all(): try: new_measurement = DeviceMeasurements() new_measurement.name = "Output (Volume)" new_measurement.device_id = each_pid.unique_id new_measurement.measurement = 'volume' new_measurement.unit = 'ml' new_measurement.channel = 8 session.add(new_measurement) if each_pid.raise_output_id: output_raise = session.query(Output).filter( Output.unique_id == each_pid.raise_output_id).first()
def page_output(): """Display Output page options.""" output_type = request.args.get('output_type', None) output_id = request.args.get('output_id', None) each_output = None if output_type in ['entry', 'options'] and output_id != '0': each_output = Output.query.filter( Output.unique_id == output_id).first() camera = Camera.query.all() function = CustomController.query.all() input_dev = Input.query.all() method = Method.query.all() misc = Misc.query.first() output = Output.query.all() output_channel = OutputChannel pid = PID.query.all() user = User.query.all() dict_outputs = parse_output_information() form_add_output = forms_output.OutputAdd() form_mod_output = forms_output.OutputMod() # Generate all measurement and units used dict_measurements = add_custom_measurements(Measurement.query.all()) dict_units = add_custom_units(Unit.query.all()) 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.query.all(), dict_outputs) choices_pid = utils_general.choices_pids(pid, dict_units, dict_measurements) custom_options_values_outputs = parse_custom_option_values_json( output, dict_controller=dict_outputs) custom_options_values_output_channels = parse_custom_option_values_output_channels_json( output_channel.query.all(), dict_controller=dict_outputs, key_name='custom_channel_options') custom_commands = {} for each_output_dev in output: if 'custom_commands' in dict_outputs[each_output_dev.output_type]: custom_commands[each_output_dev.output_type] = True # Create dict of Input names names_output = {} all_elements = output for each_element in all_elements: names_output[each_element.unique_id] = '[{id}] {name}'.format( id=each_element.unique_id.split('-')[0], name=each_element.name) # Create list of file names from the output_options directory # Used in generating the correct options for each output/device output_templates = [] output_path = os.path.join( INSTALL_DIRECTORY, 'mycodo/mycodo_flask/templates/pages/output_options') for (_, _, file_names) in os.walk(output_path): output_templates.extend(file_names) break display_order_output = csv_to_list_of_str( DisplayOrder.query.first().output) output_variables = {} for each_output_dev in output: output_variables[each_output_dev.unique_id] = {} for each_channel in dict_outputs[ each_output_dev.output_type]['channels_dict']: output_variables[each_output_dev.unique_id][each_channel] = {} output_variables[ each_output_dev.unique_id][each_channel]['amps'] = None output_variables[each_output_dev. unique_id][each_channel]['trigger_startup'] = None # Find FTDI devices ftdi_devices = [] if not current_app.config['TESTING']: for each_output_dev in output: if each_output_dev.interface == "FTDI": from mycodo.devices.atlas_scientific_ftdi import get_ftdi_device_list ftdi_devices = get_ftdi_device_list() break if not output_type: return render_template( 'pages/output.html', camera=camera, choices_function=choices_function, choices_input=choices_input, choices_input_devices=choices_input_devices, choices_method=choices_method, choices_output=choices_output, choices_output_channels=choices_output_channels, choices_pid=choices_pid, custom_commands=custom_commands, custom_options_values_outputs=custom_options_values_outputs, custom_options_values_output_channels= custom_options_values_output_channels, dict_outputs=dict_outputs, display_order_output=display_order_output, form_add_output=form_add_output, form_mod_output=form_mod_output, ftdi_devices=ftdi_devices, misc=misc, names_output=names_output, output=output, output_channel=output_channel, output_types=output_types(), output_templates=output_templates, output_variables=output_variables, user=user) elif output_type == 'entry': return render_template( 'pages/output_entry.html', camera=camera, choices_function=choices_function, choices_input=choices_input, choices_input_devices=choices_input_devices, choices_method=choices_method, choices_output=choices_output, choices_output_channels=choices_output_channels, choices_pid=choices_pid, custom_commands=custom_commands, custom_options_values_outputs=custom_options_values_outputs, custom_options_values_output_channels= custom_options_values_output_channels, dict_outputs=dict_outputs, display_order_output=display_order_output, each_output=each_output, form_add_output=form_add_output, form_mod_output=form_mod_output, ftdi_devices=ftdi_devices, misc=misc, names_output=names_output, output=output, output_channel=output_channel, output_types=output_types(), output_templates=output_templates, output_variables=output_variables, user=user) elif output_type == 'options': return render_template( 'pages/output_options.html', camera=camera, choices_function=choices_function, choices_input=choices_input, choices_input_devices=choices_input_devices, choices_method=choices_method, choices_output=choices_output, choices_output_channels=choices_output_channels, choices_pid=choices_pid, custom_commands=custom_commands, custom_options_values_outputs=custom_options_values_outputs, custom_options_values_output_channels= custom_options_values_output_channels, dict_outputs=dict_outputs, display_order_output=display_order_output, each_output=each_output, form_add_output=form_add_output, form_mod_output=form_mod_output, ftdi_devices=ftdi_devices, misc=misc, names_output=names_output, output=output, output_channel=output_channel, output_types=output_types(), output_templates=output_templates, output_variables=output_variables, user=user)
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_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 if function_type in ['entry', 'options', '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': if action_id: each_action = Actions.query.filter( Actions.unique_id == action_id).first() if function_type == 'conditions': if condition_id: each_condition = ConditionalConditions.query.filter( ConditionalConditions.unique_id == condition_id).first() 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() actions = Actions.query.all() input_dev = Input.query.all() lcd = LCD.query.all() math = Math.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_measurement = forms_measurement.MeasurementMod() 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_function.Actions() dict_controllers = parse_function_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') # TODO: Update actions to use single-file modules and be consistent with other custom_options custom_options_values_actions = {} for each_action in actions: try: custom_options_values_actions[each_action.unique_id] = json.loads( each_action.custom_options) except: custom_options_values_actions[each_action.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_actions = {} for choice_function in function: if 'custom_actions' in dict_controllers[choice_function.device]: custom_actions[choice_function.device] = True 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_math = utils_general.choices_maths(math, dict_units, dict_measurements) choices_method = utils_general.choices_methods(method) choices_output = utils_general.choices_outputs(output, 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_measurements_units = utils_general.choices_measurements_units( measurement, unit) choices_controller_ids = utils_general.choices_controller_ids() actions_dict = {'conditional': {}, 'trigger': {}} for each_action in actions: if (each_action.function_type == 'conditional' and each_action.unique_id not in actions_dict['conditional']): actions_dict['conditional'][each_action.function_id] = True if (each_action.function_type == 'trigger' and each_action.unique_id not in actions_dict['trigger']): actions_dict['trigger'][each_action.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), ('LCD', lcd), ('Math', math), ('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] = {} try: sun = Sun(latitude=each_trigger.latitude, longitude=each_trigger.longitude, zenith=each_trigger.zenith) sunrise = sun.get_sunrise_time()['time_local'] sunset = sun.get_sunset_time()['time_local'] # Adjust for date offset new_date = datetime.datetime.now() + datetime.timedelta( days=each_trigger.date_offset_days) sun = Sun(latitude=each_trigger.latitude, longitude=each_trigger.longitude, zenith=each_trigger.zenith, day=new_date.day, month=new_date.month, year=new_date.year, offset_minutes=each_trigger.time_offset_minutes) offset_rise = sun.get_sunrise_time()['time_local'] offset_set = sun.get_sunset_time()['time_local'] 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'] = None sunrise_set_calc[each_trigger.unique_id]['sunrise'] = None sunrise_set_calc[ each_trigger.unique_id]['offset_sunrise'] = None sunrise_set_calc[ each_trigger.unique_id]['offset_sunset'] = None if not function_type: return render_template( 'pages/function.html', and_=and_, actions=actions, 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_math=choices_math, 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, conditional_conditions_list=CONDITIONAL_CONDITIONS, conditional=conditional, conditional_conditions=conditional_conditions, conditions_dict=conditions_dict, controllers=controllers, function=function, function_channel=function_channel, custom_actions=custom_actions, 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_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_measurement=form_mod_measurement, 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_action_info=FUNCTION_ACTION_INFO, function_dev=function_dev, function_types=FUNCTIONS, input=input_dev, lcd=lcd, math=math, 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_, actions=actions, 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_math=choices_math, 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, conditional_conditions_list=CONDITIONAL_CONDITIONS, conditional=conditional, conditional_conditions=conditional_conditions, conditions_dict=conditions_dict, controllers=controllers, function=function, function_channel=function_channel, custom_actions=custom_actions, 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_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_measurement=form_mod_measurement, 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_action_info=FUNCTION_ACTION_INFO, function_dev=function_dev, function_types=FUNCTIONS, input=input_dev, lcd=lcd, math=math, 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_, actions=actions, 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_math=choices_math, 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, conditional_conditions_list=CONDITIONAL_CONDITIONS, conditional=conditional, conditional_conditions=conditional_conditions, conditions_dict=conditions_dict, controllers=controllers, each_function=each_function, function=function, function_channel=function_channel, custom_actions=custom_actions, 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_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_measurement=form_mod_measurement, 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_action_info=FUNCTION_ACTION_INFO, function_dev=function_dev, function_types=FUNCTIONS, input=input_dev, lcd=lcd, math=math, 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/function_options/actions.html', and_=and_, actions=actions, 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_math=choices_math, 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, conditional_conditions_list=CONDITIONAL_CONDITIONS, conditional=conditional, conditional_conditions=conditional_conditions, conditions_dict=conditions_dict, controllers=controllers, each_action=each_action, each_function=each_function, function=function, function_channel=function_channel, custom_actions=custom_actions, 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_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_measurement=form_mod_measurement, 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_action_info=FUNCTION_ACTION_INFO, function_dev=function_dev, function_types=FUNCTIONS, input=input_dev, lcd=lcd, math=math, 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_, actions=actions, 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_math=choices_math, 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, conditional_conditions_list=CONDITIONAL_CONDITIONS, conditional=conditional, conditional_conditions=conditional_conditions, conditions_dict=conditions_dict, controllers=controllers, each_action=each_action, each_condition=each_condition, each_function=each_function, function=function, function_channel=function_channel, custom_actions=custom_actions, 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_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_measurement=form_mod_measurement, 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_action_info=FUNCTION_ACTION_INFO, function_dev=function_dev, function_types=FUNCTIONS, input=input_dev, lcd=lcd, math=math, 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) each_input = None if input_type in ['entry', 'options']: each_input = Input.query.filter(Input.unique_id == input_id).first() function = CustomController.query.all() input_dev = Input.query.all() input_channel = InputChannel.query.all() math = Math.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) display_order_math = csv_to_list_of_str(DisplayOrder.query.first().math) form_add_input = forms_input.InputAdd() form_mod_input = forms_input.InputMod() form_mod_math = forms_math.MathMod() form_mod_math_measurement = forms_math.MathMeasurementMod() form_mod_average_single = forms_math.MathModAverageSingle() form_mod_sum_single = forms_math.MathModSumSingle() form_mod_redundancy = forms_math.MathModRedundancy() form_mod_difference = forms_math.MathModDifference() form_mod_equation = forms_math.MathModEquation() form_mod_humidity = forms_math.MathModHumidity() form_mod_verification = forms_math.MathModVerification() form_mod_misc = forms_math.MathModMisc() dict_inputs = parse_input_information() if request.method == 'POST': # TODO: Remove entire POST section and remove Math controllers if not utils_general.user_has_permission('edit_controllers'): return redirect(url_for('routes_input.page_input')) # Mod Math Measurement if form_mod_math_measurement.math_measurement_mod.data: utils_math.math_measurement_mod(form_mod_math_measurement) # Mod other Math settings elif form_mod_math.math_mod.data: math_type = Math.query.filter( Math.unique_id == form_mod_math.math_id.data).first().math_type if math_type == 'humidity': utils_math.math_mod(form_mod_math, form_mod_humidity) elif math_type == 'average_single': utils_math.math_mod(form_mod_math, form_mod_average_single) elif math_type == 'sum_single': utils_math.math_mod(form_mod_math, form_mod_sum_single) elif math_type == 'redundancy': utils_math.math_mod(form_mod_math, form_mod_redundancy) elif math_type == 'difference': utils_math.math_mod(form_mod_math, form_mod_difference) elif math_type == 'equation': utils_math.math_mod(form_mod_math, form_mod_equation) elif math_type == 'verification': utils_math.math_mod(form_mod_math, form_mod_verification) elif math_type == 'vapor_pressure_deficit': utils_math.math_mod(form_mod_math, form_mod_misc) else: utils_math.math_mod(form_mod_math) elif form_mod_math.math_delete.data: utils_math.math_del(form_mod_math) elif form_mod_math.math_order_up.data: utils_math.math_reorder(form_mod_math.math_id.data, display_order_math, 'up') elif form_mod_math.math_order_down.data: utils_math.math_reorder(form_mod_math.math_id.data, display_order_math, 'down') elif form_mod_math.math_activate.data: utils_math.math_activate(form_mod_math) elif form_mod_math.math_deactivate.data: utils_math.math_deactivate(form_mod_math) return redirect(url_for('routes_input.page_input')) 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_actions = {} for each_input in input_dev: if 'custom_actions' in dict_inputs[each_input.device]: custom_actions[each_input.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) # 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_math = utils_general.choices_maths(math, dict_units, dict_measurements) choices_method = utils_general.choices_methods(method) choices_output = utils_general.choices_outputs(output, 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 dict of Math names names_math = {} all_elements = math for each_element in all_elements: names_math[ 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 math_options directory # Used in generating the correct options for each math controller math_templates = [] math_path = os.path.join( INSTALL_DIRECTORY, 'mycodo/mycodo_flask/templates/pages/data_options/math_options') for (_, _, file_names) in os.walk(math_path): math_templates.extend(file_names) break # 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 # If DS18B20 inputs added, compile a list of detected inputs devices_1wire_w1thermsensor = [] 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_w1thermsensor.append({ 'name': each_name, 'value': each_name.split('-')[1] }) # Add 1-wire devices from ow-shell (if installed) devices_1wire_ow_shell = [] if 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 in input_dev: if each_input.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_, choices_function=choices_function, choices_input=choices_input, choices_math=choices_math, 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_actions=custom_actions, custom_options_values_inputs=custom_options_values_inputs, custom_options_values_input_channels= custom_options_values_input_channels, dict_inputs=dict_inputs, dict_measurements=dict_measurements, dict_units=dict_units, display_order_input=display_order_input, display_order_math=display_order_math, form_add_input=form_add_input, form_mod_input=form_mod_input, form_mod_average_single=form_mod_average_single, form_mod_sum_single=form_mod_sum_single, form_mod_redundancy=form_mod_redundancy, form_mod_difference=form_mod_difference, form_mod_equation=form_mod_equation, form_mod_humidity=form_mod_humidity, form_mod_math=form_mod_math, form_mod_math_measurement=form_mod_math_measurement, form_mod_verification=form_mod_verification, form_mod_misc=form_mod_misc, ftdi_devices=ftdi_devices, input_channel=input_channel, input_templates=input_templates, math_info=MATH_INFO, math_templates=math_templates, names_input=names_input, names_math=names_math, output=output, output_types=output_types(), pid=pid, table_conversion=Conversion, table_device_measurements=DeviceMeasurements, table_input=Input, table_math=Math, user=user, devices_1wire_ow_shell=devices_1wire_ow_shell, devices_1wire_w1thermsensor=devices_1wire_w1thermsensor) elif input_type == 'entry': return render_template( 'pages/data_options/input_entry.html', and_=and_, choices_function=choices_function, choices_input=choices_input, choices_math=choices_math, 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_actions=custom_actions, custom_options_values_inputs=custom_options_values_inputs, custom_options_values_input_channels= custom_options_values_input_channels, dict_inputs=dict_inputs, dict_measurements=dict_measurements, dict_units=dict_units, display_order_input=display_order_input, display_order_math=display_order_math, each_input=each_input, form_add_input=form_add_input, form_mod_input=form_mod_input, form_mod_average_single=form_mod_average_single, form_mod_sum_single=form_mod_sum_single, form_mod_redundancy=form_mod_redundancy, form_mod_difference=form_mod_difference, form_mod_equation=form_mod_equation, form_mod_humidity=form_mod_humidity, form_mod_math=form_mod_math, form_mod_math_measurement=form_mod_math_measurement, form_mod_verification=form_mod_verification, form_mod_misc=form_mod_misc, ftdi_devices=ftdi_devices, input_channel=input_channel, input_templates=input_templates, math_info=MATH_INFO, math_templates=math_templates, names_input=names_input, names_math=names_math, output=output, output_types=output_types(), pid=pid, table_conversion=Conversion, table_device_measurements=DeviceMeasurements, table_input=Input, table_math=Math, user=user, devices_1wire_ow_shell=devices_1wire_ow_shell, devices_1wire_w1thermsensor=devices_1wire_w1thermsensor) elif input_type == 'options': return render_template( 'pages/data_options/input_options.html', and_=and_, choices_function=choices_function, choices_input=choices_input, choices_math=choices_math, 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_actions=custom_actions, custom_options_values_inputs=custom_options_values_inputs, custom_options_values_input_channels= custom_options_values_input_channels, dict_inputs=dict_inputs, dict_measurements=dict_measurements, dict_units=dict_units, display_order_input=display_order_input, display_order_math=display_order_math, each_input=each_input, form_add_input=form_add_input, form_mod_input=form_mod_input, form_mod_average_single=form_mod_average_single, form_mod_sum_single=form_mod_sum_single, form_mod_redundancy=form_mod_redundancy, form_mod_difference=form_mod_difference, form_mod_equation=form_mod_equation, form_mod_humidity=form_mod_humidity, form_mod_math=form_mod_math, form_mod_math_measurement=form_mod_math_measurement, form_mod_verification=form_mod_verification, form_mod_misc=form_mod_misc, ftdi_devices=ftdi_devices, input_channel=input_channel, input_templates=input_templates, math_info=MATH_INFO, math_templates=math_templates, names_input=names_input, names_math=names_math, output=output, output_types=output_types(), pid=pid, table_conversion=Conversion, table_device_measurements=DeviceMeasurements, table_input=Input, table_math=Math, user=user, devices_1wire_ow_shell=devices_1wire_ow_shell, devices_1wire_w1thermsensor=devices_1wire_w1thermsensor)
def initialize_variables(self): """Set PID parameters""" self.set_log_level_debug(self.log_level_debug) self.dict_outputs = parse_output_information() self.sample_rate = db_retrieve_table_daemon( Misc, entry='first').sample_rate_controller_pid self.device_measurements = db_retrieve_table_daemon( DeviceMeasurements) pid = db_retrieve_table_daemon(PID, unique_id=self.unique_id) self.device_id = pid.measurement.split(',')[0] self.measurement_id = pid.measurement.split(',')[1] self.is_activated = pid.is_activated self.is_held = pid.is_held self.is_paused = pid.is_paused self.log_level_debug = pid.log_level_debug self.setpoint_tracking_type = pid.setpoint_tracking_type self.setpoint_tracking_id = pid.setpoint_tracking_id self.setpoint_tracking_max_age = pid.setpoint_tracking_max_age self.raise_output_id = pid.raise_output_id self.raise_output_type = pid.raise_output_type self.raise_min_duration = pid.raise_min_duration self.raise_max_duration = pid.raise_max_duration self.raise_min_off_duration = pid.raise_min_off_duration self.raise_always_min_pwm = pid.raise_always_min_pwm self.lower_output_id = pid.lower_output_id self.lower_output_type = pid.lower_output_type self.lower_min_duration = pid.lower_min_duration self.lower_max_duration = pid.lower_max_duration self.lower_min_off_duration = pid.lower_min_off_duration self.lower_always_min_pwm = pid.lower_always_min_pwm self.period = pid.period self.start_offset = pid.start_offset self.max_measure_age = pid.max_measure_age self.store_lower_as_negative = pid.store_lower_as_negative self.timer = time.time() + self.start_offset self.setpoint = pid.setpoint # Initialize PID Controller if self.PID_Controller is None: self.PID_Controller = PIDControl( self.logger, pid.setpoint, pid.p, pid.i, pid.d, pid.direction, pid.band, pid.integrator_min, pid.integrator_max) else: # Set PID options self.PID_Controller.setpoint = pid.setpoint self.PID_Controller.Kp = pid.p self.PID_Controller.Ki = pid.i self.PID_Controller.Kd = pid.d self.PID_Controller.direction = pid.direction self.PID_Controller.band = pid.band self.PID_Controller.integrator_min = pid.integrator_min self.PID_Controller.integrator_max = pid.integrator_max self.PID_Controller.first_start = True # Autotune options self.autotune_activated = pid.autotune_activated self.autotune_noiseband = pid.autotune_noiseband self.autotune_outstep = pid.autotune_outstep # If activated, initialize PID Autotune if self.autotune_activated: self.autotune_timestamp = time.time() try: self.autotune = PIDAutotune( self.PID_Controller.setpoint, out_step=self.autotune_outstep, sampletime=self.period, out_min=0, out_max=self.period, noiseband=self.autotune_noiseband) except Exception as msg: self.logger.error(msg) self.stop_controller(deactivate_pid=True) if self.setpoint_tracking_type == 'method' and self.setpoint_tracking_id != '': self.setup_method(self.setpoint_tracking_id) if self.is_paused: self.logger.info("Starting Paused") elif self.is_held: self.logger.info("Starting Held") self.logger.info("PID Settings: {}".format(self.pid_parameters_str())) return "success"
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 # 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_controller_information(), parse_input_information(), parse_output_information(), CALIBRATION_INFO, CAMERA_INFO, FUNCTION_ACTION_INFO, FUNCTION_INFO, LCD_INFO, MATH_INFO, METHOD_INFO, ] for each_section in list_dependencies: for each_device in each_section: if device in each_section: for each_device_, each_val in each_section[device].items(): if each_device_ in ['name', 'input_name']: device_name = each_val # 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]: 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, 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)
def pid_mod(form_mod_pid_base, form_mod_pid_pwm_raise, form_mod_pid_pwm_lower, form_mod_pid_output_raise, form_mod_pid_output_lower, form_mod_pid_value_raise, form_mod_pid_value_lower, form_mod_pid_volume_raise, form_mod_pid_volume_lower): action = '{action} {controller}'.format( action=TRANSLATIONS['modify']['title'], controller=TRANSLATIONS['pid']['title']) error = [] dict_outputs = parse_output_information() if not form_mod_pid_base.validate(): error.append(TRANSLATIONS['error']['title']) flash_form_errors(form_mod_pid_base) mod_pid = PID.query.filter( PID.unique_id == form_mod_pid_base.function_id.data).first() mod_pid.name = form_mod_pid_base.name.data mod_pid.measurement = form_mod_pid_base.measurement.data mod_pid.direction = form_mod_pid_base.direction.data mod_pid.period = form_mod_pid_base.period.data mod_pid.log_level_debug = form_mod_pid_base.log_level_debug.data mod_pid.start_offset = form_mod_pid_base.start_offset.data mod_pid.max_measure_age = form_mod_pid_base.max_measure_age.data mod_pid.setpoint = form_mod_pid_base.setpoint.data mod_pid.band = abs(form_mod_pid_base.band.data) mod_pid.store_lower_as_negative = form_mod_pid_base.store_lower_as_negative.data mod_pid.p = form_mod_pid_base.k_p.data mod_pid.i = form_mod_pid_base.k_i.data mod_pid.d = form_mod_pid_base.k_d.data mod_pid.integrator_min = form_mod_pid_base.integrator_max.data mod_pid.integrator_max = form_mod_pid_base.integrator_min.data mod_pid.setpoint_tracking_type = form_mod_pid_base.setpoint_tracking_type.data if form_mod_pid_base.setpoint_tracking_type.data == 'method': mod_pid.setpoint_tracking_id = form_mod_pid_base.setpoint_tracking_method_id.data elif form_mod_pid_base.setpoint_tracking_type.data == 'input-math': mod_pid.setpoint_tracking_id = form_mod_pid_base.setpoint_tracking_input_math_id.data if form_mod_pid_base.setpoint_tracking_max_age.data: mod_pid.setpoint_tracking_max_age = form_mod_pid_base.setpoint_tracking_max_age.data else: mod_pid.setpoint_tracking_max_age = 120 else: mod_pid.setpoint_tracking_id = '' # Change measurement information if ',' in form_mod_pid_base.measurement.data: measurement_id = form_mod_pid_base.measurement.data.split(',')[1] selected_measurement = get_measurement(measurement_id) measurements = DeviceMeasurements.query.filter( DeviceMeasurements.device_id == form_mod_pid_base.function_id.data).all() for each_measurement in measurements: # Only set channels 0, 1, 2 if each_measurement.channel in [0, 1, 2]: each_measurement.measurement = selected_measurement.measurement each_measurement.unit = selected_measurement.unit # # Handle Raise Output Settings # if form_mod_pid_base.raise_output_id.data: output_id = form_mod_pid_base.raise_output_id.data.split(",")[0] channel_id = form_mod_pid_base.raise_output_id.data.split(",")[1] raise_output_type = Output.query.filter( Output.unique_id == output_id).first().output_type def default_raise_output_settings(mod): if mod.raise_output_type == 'on_off': mod.raise_min_duration = 0 mod.raise_max_duration = 0 mod.raise_min_off_duration = 0 elif mod.raise_output_type == 'pwm': mod.raise_min_duration = 2 mod.raise_max_duration = 98 elif mod.raise_output_type == 'value': mod.raise_min_duration = 0 mod.raise_max_duration = 0 elif mod.raise_output_type == 'volume': mod.raise_min_duration = 0 mod.raise_max_duration = 0 return mod raise_output_id_changed = False if mod_pid.raise_output_id != form_mod_pid_base.raise_output_id.data: mod_pid.raise_output_id = form_mod_pid_base.raise_output_id.data raise_output_id_changed = True # Output ID changed if ('output_types' in dict_outputs[raise_output_type] and mod_pid.raise_output_id and raise_output_id_changed): if len(dict_outputs[raise_output_type]['output_types']) == 1: mod_pid.raise_output_type = dict_outputs[raise_output_type]['output_types'][0] else: mod_pid.raise_output_type = None mod_pid = default_raise_output_settings(mod_pid) # Output ID unchanged elif ('output_types' in dict_outputs[raise_output_type] and mod_pid.raise_output_id and not raise_output_id_changed): if (not mod_pid.raise_output_type or mod_pid.raise_output_type != form_mod_pid_base.raise_output_type.data): if len(dict_outputs[raise_output_type]['output_types']) > 1: mod_pid.raise_output_type = form_mod_pid_base.raise_output_type.data mod_pid = default_raise_output_settings(mod_pid) elif mod_pid.raise_output_type == 'on_off': if not form_mod_pid_output_raise.validate(): error.append(TRANSLATIONS['error']['title']) flash_form_errors(form_mod_pid_output_raise) else: mod_pid.raise_min_duration = form_mod_pid_output_raise.raise_min_duration.data mod_pid.raise_max_duration = form_mod_pid_output_raise.raise_max_duration.data mod_pid.raise_min_off_duration = form_mod_pid_output_raise.raise_min_off_duration.data elif mod_pid.raise_output_type == 'pwm': if not form_mod_pid_pwm_raise.validate(): error.append(TRANSLATIONS['error']['title']) flash_form_errors(form_mod_pid_pwm_raise) else: mod_pid.raise_min_duration = form_mod_pid_pwm_raise.raise_min_duty_cycle.data mod_pid.raise_max_duration = form_mod_pid_pwm_raise.raise_max_duty_cycle.data mod_pid.raise_always_min_pwm = form_mod_pid_pwm_raise.raise_always_min_pwm.data elif mod_pid.raise_output_type == 'value': if not form_mod_pid_value_raise.validate(): error.append(TRANSLATIONS['error']['title']) flash_form_errors(form_mod_pid_value_raise) else: mod_pid.raise_min_duration = form_mod_pid_value_raise.raise_min_amount.data mod_pid.raise_max_duration = form_mod_pid_value_raise.raise_max_amount.data elif mod_pid.raise_output_type == 'volume': if not form_mod_pid_volume_raise.validate(): error.append(TRANSLATIONS['error']['title']) flash_form_errors(form_mod_pid_volume_raise) else: mod_pid.raise_min_duration = form_mod_pid_volume_raise.raise_min_amount.data mod_pid.raise_max_duration = form_mod_pid_volume_raise.raise_max_amount.data else: mod_pid.raise_output_id = None # # Handle Lower Output Settings # if form_mod_pid_base.lower_output_id.data: output_id = form_mod_pid_base.lower_output_id.data.split(",")[0] channel_id = form_mod_pid_base.lower_output_id.data.split(",")[1] lower_output_type = Output.query.filter( Output.unique_id == output_id).first().output_type def default_lower_output_settings(mod): if mod.lower_output_type == 'on_off': mod.lower_min_duration = 0 mod.lower_max_duration = 0 mod.lower_min_off_duration = 0 elif mod.lower_output_type == 'pwm': mod.lower_min_duration = 2 mod.lower_max_duration = 98 elif mod.lower_output_type == 'value': mod.lower_min_duration = 0 mod.lower_max_duration = 0 elif mod.lower_output_type == 'volume': mod.lower_min_duration = 0 mod.lower_max_duration = 0 return mod lower_output_id_changed = False if mod_pid.lower_output_id != form_mod_pid_base.lower_output_id.data: mod_pid.lower_output_id = form_mod_pid_base.lower_output_id.data lower_output_id_changed = True # Output ID changed if ('output_types' in dict_outputs[lower_output_type] and mod_pid.lower_output_id and lower_output_id_changed): if len(dict_outputs[lower_output_type]['output_types']) == 1: mod_pid.lower_output_type = dict_outputs[lower_output_type]['output_types'][0] else: mod_pid.lower_output_type = None mod_pid = default_lower_output_settings(mod_pid) # Output ID unchanged elif ('output_types' in dict_outputs[lower_output_type] and mod_pid.lower_output_id and not lower_output_id_changed): if (not mod_pid.lower_output_type or mod_pid.lower_output_type != form_mod_pid_base.lower_output_type.data): if len(dict_outputs[lower_output_type]['output_types']) > 1: mod_pid.lower_output_type = form_mod_pid_base.lower_output_type.data mod_pid = default_lower_output_settings(mod_pid) elif mod_pid.lower_output_type == 'on_off': if not form_mod_pid_output_lower.validate(): error.append(TRANSLATIONS['error']['title']) flash_form_errors(form_mod_pid_output_lower) else: mod_pid.lower_min_duration = form_mod_pid_output_lower.lower_min_duration.data mod_pid.lower_max_duration = form_mod_pid_output_lower.lower_max_duration.data mod_pid.lower_min_off_duration = form_mod_pid_output_lower.lower_min_off_duration.data elif mod_pid.lower_output_type == 'pwm': if not form_mod_pid_pwm_lower.validate(): error.append(TRANSLATIONS['error']['title']) flash_form_errors(form_mod_pid_pwm_lower) else: mod_pid.lower_min_duration = form_mod_pid_pwm_lower.lower_min_duty_cycle.data mod_pid.lower_max_duration = form_mod_pid_pwm_lower.lower_max_duty_cycle.data mod_pid.lower_always_min_pwm = form_mod_pid_pwm_lower.lower_always_min_pwm.data elif mod_pid.lower_output_type == 'value': if not form_mod_pid_value_lower.validate(): error.append(TRANSLATIONS['error']['title']) flash_form_errors(form_mod_pid_value_lower) else: mod_pid.lower_min_duration = form_mod_pid_value_lower.lower_min_amount.data mod_pid.lower_max_duration = form_mod_pid_value_lower.lower_max_amount.data elif mod_pid.lower_output_type == 'volume': if not form_mod_pid_volume_lower.validate(): error.append(TRANSLATIONS['error']['title']) flash_form_errors(form_mod_pid_volume_lower) else: mod_pid.lower_min_duration = form_mod_pid_volume_lower.lower_min_amount.data mod_pid.lower_max_duration = form_mod_pid_volume_lower.lower_max_amount.data else: mod_pid.lower_output_id = None if (mod_pid.raise_output_id and mod_pid.lower_output_id and mod_pid.raise_output_id == mod_pid.lower_output_id): error.append(gettext("Raise and lower outputs cannot be the same")) try: if not error: db.session.commit() # If the controller is active or paused, refresh variables in thread if mod_pid.is_activated: control = DaemonControl() return_value = control.pid_mod(form_mod_pid_base.function_id.data) flash("PID Controller settings refresh response: " "{resp}".format(resp=return_value), "success") except Exception as except_msg: error.append(except_msg) flash_success_errors(error, action, url_for('routes_page.page_function'))
def output_mod(form_output, request_form): action = '{action} {controller}'.format( action=TRANSLATIONS['modify']['title'], controller=TRANSLATIONS['output']['title']) error = [] dict_outputs = parse_output_information() try: mod_output = Output.query.filter( Output.unique_id == form_output.output_id.data).first() if (form_output.uart_location.data and not os.path.exists(form_output.uart_location.data)): error.append( gettext( "Invalid device or improper permissions to read device")) mod_output.name = form_output.name.data if form_output.location.data: mod_output.location = form_output.location.data if form_output.i2c_location.data: mod_output.i2c_location = form_output.i2c_location.data if form_output.ftdi_location.data: mod_output.ftdi_location = form_output.ftdi_location.data if form_output.uart_location.data: mod_output.uart_location = form_output.uart_location.data if form_output.gpio_location.data: if not is_int(form_output.gpio_location.data): error.append("BCM GPIO Pin must be an integer") else: mod_output.pin = form_output.gpio_location.data mod_output.i2c_bus = form_output.i2c_bus.data mod_output.baud_rate = form_output.baud_rate.data mod_output.log_level_debug = form_output.log_level_debug.data mod_output.amps = form_output.amps.data mod_output.trigger_functions_at_start = form_output.trigger_functions_at_start.data mod_output.location = form_output.location.data mod_output.output_mode = form_output.output_mode.data if form_output.on_state.data in ["0", "1"]: mod_output.on_state = bool(int(form_output.on_state.data)) # Wireless options mod_output.protocol = form_output.protocol.data mod_output.pulse_length = form_output.pulse_length.data # Command options mod_output.on_command = form_output.on_command.data mod_output.off_command = form_output.off_command.data mod_output.force_command = form_output.force_command.data # PWM options mod_output.pwm_hertz = form_output.pwm_hertz.data mod_output.pwm_library = form_output.pwm_library.data mod_output.pwm_invert_signal = form_output.pwm_invert_signal.data # Pump options if form_output.flow_rate.data: if (mod_output.output_type == 'atlas_ezo_pmp' and (form_output.flow_rate.data > 105 or form_output.flow_rate.data < 0.5)): error.append( "The Atlas Scientific Flow Rate must be between 0.5 and 105 ml/min" ) elif form_output.flow_rate.data <= 0: error.append("Flow Rate must be a positive value") else: mod_output.flow_rate = form_output.flow_rate.data mod_output.pwm_command = form_output.pwm_command.data mod_output.pwm_invert_signal = form_output.pwm_invert_signal.data mod_output.linux_command_user = form_output.linux_command_user.data if form_output.state_startup.data == '-1': mod_output.state_startup = None elif form_output.state_startup.data is not None: mod_output.state_startup = form_output.state_startup.data if (hasattr(form_output, 'startup_value') and form_output.startup_value.data): mod_output.startup_value = form_output.startup_value.data if form_output.state_shutdown.data == '-1': mod_output.state_shutdown = None elif form_output.state_shutdown.data is not None: mod_output.state_shutdown = form_output.state_shutdown.data if (hasattr(form_output, 'shutdown_value') and form_output.shutdown_value.data): mod_output.shutdown_value = form_output.shutdown_value.data if 'test_before_saving' in dict_outputs[mod_output.output_type]: (constraints_pass, constraints_errors, mod_input ) = dict_outputs[mod_output.output_type]['test_before_saving']( mod_output, request_form) if constraints_pass: pass elif constraints_errors: for each_error in constraints_errors: flash(each_error, 'error') # Generate string to save from custom options error, custom_options = custom_options_return_string( error, dict_outputs, mod_output, request_form) if not error: mod_output.custom_options = custom_options db.session.commit() manipulate_output('Modify', form_output.output_id.data) except Exception as except_msg: logger.exception(1) error.append(except_msg) flash_success_errors(error, action, url_for('routes_page.page_output'))
def output_add(form_add): action = '{action} {controller}'.format( action=TRANSLATIONS['add']['title'], controller=TRANSLATIONS['output']['title']) error = [] dict_outputs = parse_output_information() output_types_dict = output_types() # only one comma should be in the output_type string if form_add.output_type.data.count(',') > 1: error.append("Invalid output module formatting. It appears there is " "a comma in either 'output_name_unique' or 'interfaces'.") if form_add.output_type.data.count(',') == 1: output_type = form_add.output_type.data.split(',')[0] output_interface = form_add.output_type.data.split(',')[1] else: output_type = '' output_interface = '' error.append( "Invalid output string (must be a comma-separated string)") if current_app.config['TESTING']: dep_unmet = False else: dep_unmet, _ = return_dependencies( form_add.output_type.data.split(',')[0]) 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=form_add.output_type.data, dep=', '.join(list_unmet_deps))) if not is_int(form_add.output_quantity.data, check_range=[1, 20]): error.append("{error}. {accepted_values}: 1-20".format( error=gettext("Invalid quantity"), accepted_values=gettext("Acceptable values"))) if not error: for _ in range(0, form_add.output_quantity.data): try: new_output = Output() try: from RPi import GPIO if GPIO.RPI_INFO['P1_REVISION'] == 1: new_output.i2c_bus = 0 else: new_output.i2c_bus = 1 except: logger.error( "RPi.GPIO and Raspberry Pi required for this action") new_output.name = "Name" new_output.output_type = output_type new_output.interface = output_interface # # Set default values for new input being added # # input add options if output_type in dict_outputs: def dict_has_value(key): if (key in dict_outputs[output_type] and dict_outputs[output_type][key] is not None): return True # # Interfacing options # if output_interface == 'I2C': if dict_has_value('i2c_address_default'): new_output.i2c_location = dict_outputs[ output_type]['i2c_address_default'] elif dict_has_value('i2c_location'): new_output.i2c_location = dict_outputs[ output_type]['i2c_location'][ 0] # First list entry if output_interface == 'FTDI': if dict_has_value('ftdi_location'): new_output.ftdi_location = dict_outputs[ output_type]['ftdi_location'] if output_interface == 'UART': if dict_has_value('uart_location'): new_output.uart_location = dict_outputs[ output_type]['uart_location'] # UART options if dict_has_value('uart_baud_rate'): new_output.baud_rate = dict_outputs[output_type][ 'uart_baud_rate'] if dict_has_value('pin_cs'): new_output.pin_cs = dict_outputs[output_type]['pin_cs'] if dict_has_value('pin_miso'): new_output.pin_miso = dict_outputs[output_type][ 'pin_miso'] if dict_has_value('pin_mosi'): new_output.pin_mosi = dict_outputs[output_type][ 'pin_mosi'] if dict_has_value('pin_clock'): new_output.pin_clock = dict_outputs[output_type][ 'pin_clock'] # Bluetooth (BT) options elif output_interface == 'BT': if dict_has_value('bt_location'): new_output.location = dict_outputs[output_type][ 'bt_location'] if dict_has_value('bt_adapter'): new_output.bt_adapter = dict_outputs[output_type][ 'bt_adapter'] # GPIO options elif output_interface == 'GPIO': if dict_has_value('gpio_pin'): new_output.pin = dict_outputs[output_type][ 'gpio_pin'] # Custom location location elif dict_has_value('location'): new_output.location = dict_outputs[output_type][ 'location']['options'][0][0] # First entry in list # # Custom Options # list_options = [] if 'custom_options' in dict_outputs[output_type]: for each_option in dict_outputs[output_type][ 'custom_options']: 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_output.custom_options = ';'.join(list_options) if output_type in output_types_dict['pwm']: new_output.pwm_hertz = 22000 new_output.pwm_library = 'pigpio_any' if output_type in output_types_dict['volume']: new_output.output_mode = 'fastest_flow_rate' new_output.flow_rate = 10 if output_type == 'atlas_ezo_pmp': if output_interface == 'FTDI': new_output.location = '/dev/ttyUSB0' elif output_interface == 'I2C': new_output.location = '0x67' new_output.i2c_bus = 1 elif output_interface == 'UART': new_output.location = '/dev/ttyAMA0' new_output.baud_rate = 9600 if output_type == 'wired': new_output.state_startup = '0' new_output.state_shutdown = '0' elif output_type == 'wireless_rpi_rf': new_output.pin = None new_output.protocol = 1 new_output.pulse_length = 189 new_output.on_command = '22559' new_output.off_command = '22558' new_output.force_command = True elif output_type == 'command': new_output.linux_command_user = '******' new_output.on_command = '/home/pi/script_on.sh' new_output.off_command = '/home/pi/script_off.sh' new_output.force_command = True elif output_type == 'command_pwm': new_output.linux_command_user = '******' new_output.pwm_command = '/home/pi/script_pwm.sh ((duty_cycle))' elif output_type == 'python': new_output.on_command = """ import datetime timestamp = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") log_string = "{ts}: ID: {id}: ON".format(id=output_id, ts=timestamp) self.logger.info(log_string)""" new_output.off_command = """ import datetime timestamp = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") log_string = "{ts}: ID: {id}: OFF".format(id=output_id, ts=timestamp) self.logger.info(log_string)""" new_output.force_command = True elif output_type == 'python_pwm': new_output.pwm_command = """ import datetime timestamp = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") log_string = "{ts}: ID: {id}: {dc} % Duty Cycle".format( dc=duty_cycle, id=output_id, ts=timestamp) self.logger.info(log_string)""" if not error: new_output.save() display_order = csv_to_list_of_str( DisplayOrder.query.first().output) DisplayOrder.query.first().output = add_display_order( display_order, new_output.unique_id) # # If measurements defined in the Output Module # if ('measurements_dict' in dict_outputs[output_type] and dict_outputs[output_type]['measurements_dict'] != []): for each_channel in dict_outputs[output_type][ 'measurements_dict']: measure_info = dict_outputs[output_type][ 'measurements_dict'][each_channel] new_measurement = DeviceMeasurements() if 'name' in measure_info: new_measurement.name = measure_info['name'] new_measurement.device_id = new_output.unique_id new_measurement.measurement = measure_info[ 'measurement'] new_measurement.unit = measure_info['unit'] new_measurement.channel = each_channel new_measurement.save() db.session.commit() if not current_app.config['TESTING']: manipulate_output('Add', new_output.unique_id) except sqlalchemy.exc.OperationalError as except_msg: error.append(except_msg) except sqlalchemy.exc.IntegrityError as except_msg: error.append(except_msg) flash_success_errors(error, action, url_for('routes_page.page_output')) if dep_unmet: return 1
from mycodo.config import INSTALL_DIRECTORY from mycodo.utils.outputs import parse_output_information save_path = os.path.join(INSTALL_DIRECTORY, "mycodo-outputs.rst") outputs_info = OrderedDict() mycodo_info = OrderedDict() def repeat_to_length(s, wanted): return (s * (wanted // len(s) + 1))[:wanted] if __name__ == "__main__": for output_id, output_data in parse_output_information( exclude_custom=True).items(): name_str = "" if 'output_manufacturer' in output_data and output_data[ 'output_manufacturer']: name_str += "{}".format(output_data['output_manufacturer']) if 'output_name' in output_data and output_data['output_name']: name_str += ": {}".format(output_data['output_name']) if 'measurements_name' in output_data and output_data[ 'measurements_name']: name_str += ": {}".format(output_data['measurements_name']) if ('output_manufacturer' in output_data and output_data['output_manufacturer'] in ['Linux', 'Mycodo', 'Raspberry Pi', 'System']): if name_str in mycodo_info and 'dependencies_module' in mycodo_info[
def return_output_usage(table_misc, table_outputs): """ Return output usage and cost """ dict_outputs = parse_output_information() date_now = datetime.date.today() time_now = datetime.datetime.now() past_month_seconds = 0 if table_misc.output_usage_dayofmonth == datetime.datetime.today().day: past_month_seconds = (time_now - time_now.replace( hour=0, minute=0, second=0, microsecond=0)).total_seconds() elif table_misc.output_usage_dayofmonth > datetime.datetime.today().day: first_day = date_now.replace(day=1) last_month = first_day - datetime.timedelta(days=1) past_month = last_month.replace(day=table_misc.output_usage_dayofmonth) past_month_seconds = (date_now - past_month).total_seconds() elif table_misc.output_usage_dayofmonth < datetime.datetime.today().day: past_month = date_now.replace(day=table_misc.output_usage_dayofmonth) past_month_seconds = (date_now - past_month).total_seconds() output_stats = OrderedDict() # Calculate output on duration for different time periods # Use OrderedDict to ensure proper order when saved to csv file output_stats['total_duration'] = dict.fromkeys( ['1d', '1w', '1m', '1m_date', '1y'], 0) output_stats['total_kwh'] = dict.fromkeys( ['1d', '1w', '1m', '1m_date', '1y'], 0) output_stats['total_cost'] = dict.fromkeys( ['1d', '1w', '1m', '1m_date', '1y'], 0) for each_output in table_outputs: if ('output_types' in dict_outputs[each_output.output_type] and 'on_off' in dict_outputs[each_output.output_type]['output_types'] and each_output.amps): past_1d_hours = output_sec_on(each_output.unique_id, 86400) / 3600 past_1w_hours = output_sec_on(each_output.unique_id, 604800) / 3600 past_1m_hours = output_sec_on(each_output.unique_id, 2629743) / 3600 past_1m_date_hours = output_sec_on(each_output.unique_id, int(past_month_seconds)) / 3600 past_1y_hours = output_sec_on(each_output.unique_id, 31556926) / 3600 past_1d_kwh = table_misc.output_usage_volts * each_output.amps * past_1d_hours / 1000 past_1w_kwh = table_misc.output_usage_volts * each_output.amps * past_1w_hours / 1000 past_1m_kwh = table_misc.output_usage_volts * each_output.amps * past_1m_hours / 1000 past_1m_date_kwh = table_misc.output_usage_volts * each_output.amps * past_1m_date_hours / 1000 past_1y_kwh = table_misc.output_usage_volts * each_output.amps * past_1y_hours / 1000 output_stats[each_output.unique_id] = { '1d': { 'hours_on': past_1d_hours, 'kwh': past_1d_kwh, 'cost': table_misc.output_usage_cost * past_1d_kwh }, '1w': { 'hours_on': past_1w_hours, 'kwh': past_1w_kwh, 'cost': table_misc.output_usage_cost * past_1w_kwh }, '1m': { 'hours_on': past_1m_hours, 'kwh': past_1m_kwh, 'cost': table_misc.output_usage_cost * past_1m_kwh }, '1m_date': { 'hours_on': past_1m_date_hours, 'kwh': past_1m_date_kwh, 'cost': table_misc.output_usage_cost * past_1m_date_kwh }, '1y': { 'hours_on': past_1y_hours, 'kwh': past_1y_kwh, 'cost': table_misc.output_usage_cost * past_1y_kwh } } output_stats['total_duration']['1d'] += past_1d_hours output_stats['total_duration']['1w'] += past_1w_hours output_stats['total_duration']['1m'] += past_1m_hours output_stats['total_duration']['1m_date'] += past_1m_date_hours output_stats['total_duration']['1y'] += past_1y_hours output_stats['total_kwh']['1d'] += past_1d_kwh output_stats['total_kwh']['1w'] += past_1w_kwh output_stats['total_kwh']['1m'] += past_1m_kwh output_stats['total_kwh']['1m_date'] += past_1m_date_kwh output_stats['total_kwh']['1y'] += past_1y_kwh output_stats['total_cost'][ '1d'] += table_misc.output_usage_cost * past_1d_kwh output_stats['total_cost'][ '1w'] += table_misc.output_usage_cost * past_1w_kwh output_stats['total_cost'][ '1m'] += table_misc.output_usage_cost * past_1m_kwh output_stats['total_cost'][ '1m_date'] += table_misc.output_usage_cost * past_1m_date_kwh output_stats['total_cost'][ '1y'] += table_misc.output_usage_cost * past_1y_kwh return output_stats
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 generate_output_usage_report(): """ Generate output usage report in a csv file """ logger.debug("Generating output usage report...") try: assure_path_exists(USAGE_REPORTS_PATH) misc = db_retrieve_table_daemon(Misc, entry='first') output = db_retrieve_table_daemon(Output) output_channel = db_retrieve_table_daemon(OutputChannel) dict_outputs = parse_output_information() custom_options_values_output_channels = parse_custom_option_values_output_channels_json( output_channel.query.all(), dict_controller=dict_outputs, key_name='custom_channel_options') output_usage = return_output_usage( dict_outputs, misc, output.all(), output_channel, custom_options_values_output_channels) timestamp = time.strftime("%Y-%m-%d_%H-%M") file_name = 'output_usage_report_{ts}.csv'.format(ts=timestamp) report_path_file = os.path.join(USAGE_REPORTS_PATH, file_name) with open(report_path_file, 'wb') as f: w = csv.writer(f) # Header row w.writerow([ 'Relay ID', 'Relay Unique ID', 'Relay Name', 'Type', 'Past Day', 'Past Week', 'Past Month', 'Past Month (from {})'.format(misc.output_usage_dayofmonth), 'Past Year' ]) for key, value in output_usage.items(): if key in ['total_duration', 'total_cost', 'total_kwh']: # Totals rows w.writerow([ '', '', '', key, value['1d'], value['1w'], value['1m'], value['1m_date'], value['1y'] ]) else: # Each output rows each_output = output.filter( Output.unique_id == key).first() w.writerow([ each_output.unique_id, each_output.unique_id, str(each_output.name).encode("utf-8"), 'hours_on', value['1d']['hours_on'], value['1w']['hours_on'], value['1m']['hours_on'], value['1m_date']['hours_on'], value['1y']['hours_on'] ]) w.writerow([ each_output.unique_id, each_output.unique_id, str(each_output.name).encode("utf-8"), 'kwh', value['1d']['kwh'], value['1w']['kwh'], value['1m']['kwh'], value['1m_date']['kwh'], value['1y']['kwh'] ]) w.writerow([ each_output.unique_id, each_output.unique_id, str(each_output.name).encode("utf-8"), 'cost', value['1d']['cost'], value['1w']['cost'], value['1m']['cost'], value['1m_date']['cost'], value['1y']['cost'] ]) set_user_grp(report_path_file, 'mycodo', 'mycodo') except Exception: logger.exception("Energy Usage Report Generation ERROR")
def output_mod(form_output, request_form): action = '{action} {controller}'.format( action=TRANSLATIONS['modify']['title'], controller=TRANSLATIONS['output']['title']) error = [] dict_outputs = parse_output_information() try: channels = OutputChannel.query.filter( OutputChannel.output_id == form_output.output_id.data).all() mod_output = Output.query.filter( Output.unique_id == form_output.output_id.data).first() if (form_output.uart_location.data and not os.path.exists(form_output.uart_location.data)): error.append(gettext( "Invalid device or improper permissions to read device")) mod_output.name = form_output.name.data if form_output.location.data: mod_output.location = form_output.location.data if form_output.i2c_location.data: mod_output.i2c_location = form_output.i2c_location.data if form_output.ftdi_location.data: mod_output.ftdi_location = form_output.ftdi_location.data if form_output.uart_location.data: mod_output.uart_location = form_output.uart_location.data if form_output.gpio_location.data: if not is_int(form_output.gpio_location.data): error.append("BCM GPIO Pin must be an integer") else: mod_output.pin = form_output.gpio_location.data if form_output.i2c_bus.data is not None: mod_output.i2c_bus = form_output.i2c_bus.data if form_output.baud_rate.data: mod_output.baud_rate = form_output.baud_rate.data mod_output.log_level_debug = form_output.log_level_debug.data # Parse pre-save custom options for output device and its channels try: custom_options_dict_presave = json.loads(mod_output.custom_options) except: logger.error("Malformed JSON") custom_options_dict_presave = {} custom_options_channels_dict_presave = {} for each_channel in channels: if each_channel.custom_options and each_channel.custom_options != "{}": custom_options_channels_dict_presave[each_channel.channel] = json.loads( each_channel.custom_options) else: custom_options_channels_dict_presave[each_channel.channel] = {} # Parse post-save custom options for output device and its channels error, custom_options_json_postsave = custom_options_return_json( error, dict_outputs, request_form, device=mod_output.output_type) custom_options_dict_postsave = json.loads(custom_options_json_postsave) custom_options_channels_dict_postsave = {} for each_channel in channels: error, custom_options_channels_json_postsave_tmp = custom_channel_options_return_json( error, dict_outputs, request_form, form_output.output_id.data, each_channel.channel, device=mod_output.output_type, use_defaults=True) custom_options_channels_dict_postsave[each_channel.channel] = json.loads( custom_options_channels_json_postsave_tmp) if 'execute_at_modification' in dict_outputs[mod_output.output_type]: # pass custom options to module prior to saving to database (allow_saving, mod_output, custom_options_dict, custom_options_channels_dict) = dict_outputs[mod_output.output_type]['execute_at_modification']( mod_output, request_form, custom_options_dict_presave, custom_options_channels_dict_presave, custom_options_dict_postsave, custom_options_channels_dict_postsave) custom_options = json.dumps(custom_options_dict) # Convert from dict to JSON string custom_channel_options = custom_options_channels_dict if not allow_saving: error.append("execute_at_modification() would not allow output options to be saved") else: # Don't pass custom options to module custom_options = json.dumps(custom_options_dict_postsave) custom_channel_options = custom_options_channels_dict_postsave # Finally, save custom options for both output and channels mod_output.custom_options = custom_options for each_channel in channels: if 'name' in custom_channel_options[each_channel.channel]: each_channel.name = custom_channel_options[each_channel.channel]['name'] each_channel.custom_options = json.dumps(custom_channel_options[each_channel.channel]) if not error: db.session.commit() manipulate_output('Modify', form_output.output_id.data) except Exception as except_msg: logger.exception(1) error.append(except_msg) flash_success_errors(error, action, url_for('routes_page.page_output'))