示例#1
0
    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))
示例#2
0
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
示例#3
0
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'])
示例#4
0
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
示例#5
0
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)
示例#6
0
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
        })
示例#7
0
    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}"
示例#8
0
    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))
示例#9
0
    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}")
示例#10
0
    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)
示例#11
0
    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}"
示例#12
0
    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())
示例#13
0
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
示例#14
0
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
示例#15
0
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
示例#16
0
                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()
示例#17
0
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)
示例#18
0
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"
示例#19
0
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"
示例#20
0
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)
示例#21
0
    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"
示例#22
0
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)
示例#23
0
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'))
示例#24
0
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'))
示例#25
0
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
示例#26
0
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[
示例#27
0
文件: tools.py 项目: stardawg/Mycodo
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
示例#28
0
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)
示例#29
0
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")
示例#30
0
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'))