Example #1
0
def settings_diagnostic():
    """ Display general settings """
    if not utils_general.user_has_permission('view_settings'):
        return redirect(url_for('routes_general.home'))

    form_settings_diagnostic = forms_settings.SettingsDiagnostic()

    if request.method == 'POST':
        if not utils_general.user_has_permission('edit_settings'):
            return redirect(url_for('routes_general.home'))

        if form_settings_diagnostic.delete_dashboard_elements.data:
            utils_settings.settings_diagnostic_delete_dashboard_elements()
        elif form_settings_diagnostic.delete_inputs.data:
            utils_settings.settings_diagnostic_delete_inputs()
        elif form_settings_diagnostic.delete_maths.data:
            utils_settings.settings_diagnostic_delete_maths()
        elif form_settings_diagnostic.delete_notes_tags.data:
            utils_settings.settings_diagnostic_delete_notes_tags()
        elif form_settings_diagnostic.delete_outputs.data:
            utils_settings.settings_diagnostic_delete_outputs()
        elif form_settings_diagnostic.delete_settings_database.data:
            utils_settings.settings_diagnostic_delete_settings_database()
        elif form_settings_diagnostic.delete_file_dependency.data:
            utils_settings.settings_diagnostic_delete_file('dependency')
        elif form_settings_diagnostic.delete_file_upgrade.data:
            utils_settings.settings_diagnostic_delete_file('upgrade')
        elif form_settings_diagnostic.reset_email_counter.data:
            utils_settings.settings_diagnostic_reset_email_counter()

        return redirect(url_for('routes_settings.settings_diagnostic'))

    return render_template('settings/diagnostic.html',
                           form_settings_diagnostic=form_settings_diagnostic)
Example #2
0
def settings_users():
    """ Display user settings """
    if not utils_general.user_has_permission('view_settings'):
        return redirect(url_for('routes_general.home'))

    users = User.query.all()
    user_roles = Role.query.all()
    form_add_user = forms_settings.UserAdd()
    form_mod_user = forms_settings.UserMod()
    form_user_roles = forms_settings.UserRoles()

    if request.method == 'POST':
        if not utils_general.user_has_permission('edit_users'):
            return redirect(url_for('routes_general.home'))

        if form_add_user.add_user.data:
            utils_settings.user_add(form_add_user)
        elif form_mod_user.delete.data:
            if utils_settings.user_del(form_mod_user) == 'logout':
                return redirect('/logout')
        elif form_mod_user.save.data:
            if utils_settings.user_mod(form_mod_user) == 'logout':
                return redirect('/logout')
        elif (form_user_roles.add_role.data or form_user_roles.save_role.data
              or form_user_roles.delete_role.data):
            utils_settings.user_roles(form_user_roles)
        return redirect(url_for('routes_settings.settings_users'))

    return render_template('settings/users.html',
                           themes=THEMES,
                           users=users,
                           user_roles=user_roles,
                           form_add_user=form_add_user,
                           form_mod_user=form_mod_user,
                           form_user_roles=form_user_roles)
Example #3
0
def settings_diagnostic():
    """ Display general settings """
    if not utils_general.user_has_permission('view_settings'):
        return redirect(url_for('routes_general.home'))

    form_settings_diagnostic = forms_settings.SettingsDiagnostic()

    if request.method == 'POST':
        if not utils_general.user_has_permission('edit_settings'):
            return redirect(url_for('routes_general.home'))

        if form_settings_diagnostic.delete_dashboard_elements.data:
            utils_settings.settings_diagnostic_delete_dashboard_elements()
        elif form_settings_diagnostic.delete_inputs.data:
            utils_settings.settings_diagnostic_delete_inputs()
        elif form_settings_diagnostic.delete_maths.data:
            utils_settings.settings_diagnostic_delete_maths()
        elif form_settings_diagnostic.delete_notes_tags.data:
            utils_settings.settings_diagnostic_delete_notes_tags()
        elif form_settings_diagnostic.delete_outputs.data:
            utils_settings.settings_diagnostic_delete_outputs()
        elif form_settings_diagnostic.delete_settings_database.data:
            utils_settings.settings_diagnostic_delete_settings_database()
        elif form_settings_diagnostic.delete_file_dependency.data:
            utils_settings.settings_diagnostic_delete_file('dependency')
        elif form_settings_diagnostic.delete_file_upgrade.data:
            utils_settings.settings_diagnostic_delete_file('upgrade')

        return redirect(url_for('routes_settings.settings_diagnostic'))

    return render_template('settings/diagnostic.html',
                           form_settings_diagnostic=form_settings_diagnostic)
Example #4
0
def settings_pi():
    """ Display general settings """
    if not utils_general.user_has_permission('view_settings'):
        return redirect(url_for('routes_general.home'))

    misc = Misc.query.first()
    form_settings_pi = forms_settings.SettingsPi()

    pi_settings = get_raspi_config_settings()

    pigpiod_sample_rate = 999
    if os.path.exists('/etc/systemd/system/pigpiod_low.service'):
        pigpiod_sample_rate = 1
    elif os.path.exists('/etc/systemd/system/pigpiod_high.service'):
        pigpiod_sample_rate = 5
    elif os.path.exists('/etc/systemd/system/pigpiod.service'):
        pigpiod_sample_rate = 1

    if request.method == 'POST':
        if not utils_general.user_has_permission('edit_settings'):
            return redirect(url_for('routes_general.home'))

        form_name = request.form['form-name']
        if form_name == 'Pi':
            utils_settings.settings_pi_mod(form_settings_pi)
        return redirect(url_for('routes_settings.settings_pi'))

    return render_template('settings/pi.html',
                           misc=misc,
                           pi_settings=pi_settings,
                           pigpiod_sample_rate=pigpiod_sample_rate,
                           form_settings_pi=form_settings_pi)
Example #5
0
def settings_input():
    """ Display measurement settings """
    if not utils_general.user_has_permission('view_settings'):
        return redirect(url_for('routes_general.home'))

    form_input = forms_settings.Input()
    form_input_delete = forms_settings.InputDel()

    dict_measurements = add_custom_measurements(Measurement.query.all())
    dict_units = add_custom_units(Unit.query.all())

    # Get list of custom inputs
    excluded_files = ['__init__.py', '__pycache__']
    install_dir = os.path.abspath(INSTALL_DIRECTORY)
    path_custom_inputs = os.path.join(install_dir,
                                      'mycodo/inputs/custom_inputs')

    if request.method == 'POST':
        if not utils_general.user_has_permission('edit_controllers'):
            return redirect(url_for('routes_general.home'))

        if form_input.import_input_upload.data:
            utils_settings.settings_input_import(form_input)
        elif form_input_delete.delete_input.data:
            utils_settings.settings_input_delete(form_input_delete)

        return redirect(url_for('routes_settings.settings_input'))

    dict_inputs = {}

    for each_file in os.listdir(path_custom_inputs):
        if each_file not in excluded_files:
            try:
                full_path_file = os.path.join(path_custom_inputs, each_file)
                input_info = load_module_from_file(full_path_file)
                dict_inputs[
                    input_info.INPUT_INFORMATION['input_name_unique']] = {}
                dict_inputs[input_info.INPUT_INFORMATION['input_name_unique']]['input_name'] = \
                    input_info.INPUT_INFORMATION['input_name']
                dict_inputs[input_info.INPUT_INFORMATION['input_name_unique']]['input_manufacturer'] = \
                    input_info.INPUT_INFORMATION['input_manufacturer']
                dict_inputs[input_info.INPUT_INFORMATION['input_name_unique']]['measurements_name'] = \
                    input_info.INPUT_INFORMATION['measurements_name']
            except:
                pass

    # dict_inputs = parse_input_information()

    return render_template('settings/input.html',
                           dict_inputs=dict_inputs,
                           dict_measurements=dict_measurements,
                           dict_units=dict_units,
                           form_input=form_input,
                           form_input_delete=form_input_delete)
Example #6
0
def settings_input():
    """ Display measurement settings """
    if not utils_general.user_has_permission('view_settings'):
        return redirect(url_for('routes_general.home'))

    form_input = forms_settings.Input()
    form_input_delete = forms_settings.InputDel()

    dict_measurements = add_custom_measurements(Measurement.query.all())
    dict_units = add_custom_units(Unit.query.all())

    # Get list of custom inputs
    excluded_files = ['__init__.py', '__pycache__']
    install_dir = os.path.abspath(INSTALL_DIRECTORY)
    path_custom_inputs = os.path.join(install_dir, 'mycodo/inputs/custom_inputs')

    if request.method == 'POST':
        if not utils_general.user_has_permission('edit_controllers'):
            return redirect(url_for('routes_general.home'))

        if form_input.import_input_upload.data:
            utils_settings.settings_input_import(form_input)
        elif form_input_delete.delete_input.data:
            utils_settings.settings_input_delete(form_input_delete)

        return redirect(url_for('routes_settings.settings_input'))

    dict_inputs = {}

    for each_file in os.listdir(path_custom_inputs):
        if each_file not in excluded_files:
            try:
                full_path_file = os.path.join(path_custom_inputs, each_file)
                input_info = load_module_from_file(full_path_file)
                dict_inputs[input_info.INPUT_INFORMATION['input_name_unique']] = {}
                dict_inputs[input_info.INPUT_INFORMATION['input_name_unique']]['input_name'] = \
                    input_info.INPUT_INFORMATION['input_name']
                dict_inputs[input_info.INPUT_INFORMATION['input_name_unique']]['input_manufacturer'] = \
                    input_info.INPUT_INFORMATION['input_manufacturer']
                dict_inputs[input_info.INPUT_INFORMATION['input_name_unique']]['measurements_name'] = \
                    input_info.INPUT_INFORMATION['measurements_name']
            except:
                pass

    # dict_inputs = parse_input_information()

    return render_template('settings/input.html',
                           dict_inputs=dict_inputs,
                           dict_measurements=dict_measurements,
                           dict_units=dict_units,
                           form_input=form_input,
                           form_input_delete=form_input_delete)
def test_123():
    """
    This endpoint will display different messages for logged in and logged out users.
    Be very careful when creating endpoints so unauthorized users don't have access
    to endpoints with sensitive information.
    """
    if not current_user.is_authenticated:
        return "You are not logged in and cannot access this endpoint"

    user = User.query.filter(User.name == current_user.name).first()
    role = Role.query.filter(Role.id == user.role_id).first()
    return_message = "You are logged in as '{}' with the role '{}' and can access this endpoint".format(
        user.name, role.name)
    if user_has_permission('edit_settings'):
        return_message += "<br/>This user has permission to Edit Settings"
    if user_has_permission('edit_controllers'):
        return_message += "<br/>This user has permission to Edit Controllers"
    if user_has_permission('edit_users'):
        return_message += "<br/>This user has permission to Edit Users"
    if user_has_permission('view_settings'):
        return_message += "<br/>This user has permission to View Settings"
    if user_has_permission('view_camera'):
        return_message += "<br/>This user has permission to View Cameras"
    if user_has_permission('view_stats'):
        return_message += "<br/>This user has permission to View Stats"
    if user_has_permission('view_logs'):
        return_message += "<br/>This user has permission to View Logs"
    if user_has_permission('reset_password'):
        return_message += "<br/>This user has permission to Reset Passwords"
    return return_message
Example #8
0
def change_theme():
    """Change theme"""
    if not utils_general.user_has_permission('view_settings'):
        return redirect(url_for('routes_general.home'))

    form_prefs = forms_settings.UserPreferences()

    if request.method == 'POST':
        if not utils_general.user_has_permission('edit_users'):
            return redirect(url_for('routes_general.home'))

        if form_prefs.user_preferences_save.data:
            utils_settings.change_preferences(form_prefs)
    return redirect(url_for('routes_general.home'))
Example #9
0
def settings_widget():
    """Display widget settings."""
    if not utils_general.user_has_permission('view_settings'):
        return redirect(url_for('routes_general.home'))

    form_widget = forms_settings.Widget()
    form_widget_delete = forms_settings.WidgetDel()

    dict_measurements = add_custom_measurements(Measurement.query.all())
    dict_units = add_custom_units(Unit.query.all())

    # Get list of custom widgets
    excluded_files = ['__init__.py', '__pycache__']

    if request.method == 'POST':
        if not utils_general.user_has_permission('edit_controllers'):
            return redirect(url_for('routes_general.home'))

        if form_widget.import_widget_upload.data:
            utils_settings.settings_widget_import(form_widget)
        elif form_widget_delete.delete_widget.data:
            utils_settings.settings_widget_delete(form_widget_delete)

        return redirect(url_for('routes_settings.settings_widget'))

    dict_widgets = {}

    for each_file in os.listdir(PATH_WIDGETS_CUSTOM):
        if each_file not in excluded_files:
            try:
                full_path_file = os.path.join(PATH_WIDGETS_CUSTOM, each_file)
                widget_info, status = load_module_from_file(
                    full_path_file, 'widgets')

                if widget_info:
                    dict_widgets[widget_info.WIDGET_INFORMATION[
                        'widget_name_unique']] = {}
                    dict_widgets[widget_info.WIDGET_INFORMATION['widget_name_unique']]['widget_name'] = \
                        widget_info.WIDGET_INFORMATION['widget_name']
                    dict_widgets[widget_info.WIDGET_INFORMATION['widget_name_unique']]['measurements_name'] = \
                        widget_info.WIDGET_INFORMATION['measurements_name']
            except:
                pass

    return render_template('settings/widget.html',
                           dict_widgets=dict_widgets,
                           dict_measurements=dict_measurements,
                           dict_units=dict_units,
                           form_widget=form_widget,
                           form_widget_delete=form_widget_delete)
Example #10
0
def settings_output():
    """ Display measurement settings """
    if not utils_general.user_has_permission('view_settings'):
        return redirect(url_for('routes_general.home'))

    form_output = forms_settings.Output()
    form_output_delete = forms_settings.OutputDel()

    dict_measurements = add_custom_measurements(Measurement.query.all())
    dict_units = add_custom_units(Unit.query.all())

    # Get list of custom outputs
    excluded_files = ['__init__.py', '__pycache__']

    if request.method == 'POST':
        if not utils_general.user_has_permission('edit_controllers'):
            return redirect(url_for('routes_general.home'))

        if form_output.import_output_upload.data:
            utils_settings.settings_output_import(form_output)
        elif form_output_delete.delete_output.data:
            utils_settings.settings_output_delete(form_output_delete)

        return redirect(url_for('routes_settings.settings_output'))

    dict_outputs = {}

    for each_file in os.listdir(PATH_OUTPUTS_CUSTOM):
        if each_file not in excluded_files:
            try:
                full_path_file = os.path.join(PATH_OUTPUTS_CUSTOM, each_file)
                output_info = load_module_from_file(full_path_file, 'outputs')
                dict_outputs[
                    output_info.OUTPUT_INFORMATION['output_name_unique']] = {}
                dict_outputs[output_info.OUTPUT_INFORMATION['output_name_unique']]['output_name'] = \
                    output_info.OUTPUT_INFORMATION['output_name']
                dict_outputs[output_info.OUTPUT_INFORMATION['output_name_unique']]['measurements_name'] = \
                    output_info.OUTPUT_INFORMATION['measurements_name']
            except:
                pass

    # dict_outputs = parse_output_information()

    return render_template('settings/output.html',
                           dict_outputs=dict_outputs,
                           dict_measurements=dict_measurements,
                           dict_units=dict_units,
                           form_output=form_output,
                           form_output_delete=form_output_delete)
Example #11
0
def remote_input():
    """Returns input information for remote administration"""
    if not utils_general.user_has_permission('edit_settings'):
        return redirect(url_for('routes_general.home'))

    remote_hosts = Remote.query.all()
    display_order_unsplit = DisplayOrder.query.first().remote_host
    if display_order_unsplit:
        display_order = display_order_unsplit.split(",")
    else:
        display_order = []

    host_auth = {}
    host_inputs = {}
    for each_host in remote_hosts:
        # Return input information about each host
        headers = remote_log_in(each_host.host, each_host.username,
                                each_host.password_hash)

        _, host_inputs[each_host.host] = remote_host_page(
            each_host.host, headers, 'remote_get_inputs')

        host_inputs[each_host.host] = json.loads(host_inputs[each_host.host])

    return render_template('remote/input.html',
                           display_order=display_order,
                           remote_hosts=remote_hosts,
                           host_auth=host_auth,
                           host_inputs=host_inputs)
Example #12
0
def remote_setup():
    """Return pages for remote administration"""
    if not utils_general.user_has_permission('edit_settings'):
        return redirect(url_for('routes_general.home'))

    remote_hosts = Remote.query.all()
    display_order_unsplit = DisplayOrder.query.first().remote_host
    if display_order_unsplit:
        display_order = display_order_unsplit.split(",")
    else:
        display_order = []

    form_setup = forms_authentication.RemoteSetup()

    if request.method == 'POST':
        if form_setup.add.data:
            utils_remote_host.remote_host_add(form_setup, display_order)
        elif form_setup.delete.data:
            utils_remote_host.remote_host_del(form_setup)
        return redirect('/remote/setup')

    host_auth = {}
    for each_host in remote_hosts:
        headers = remote_log_in(each_host.host, each_host.username,
                                each_host.password_hash)

        _, host_auth[each_host.host] = remote_host_page(
            each_host.host, headers, 'auth')

    return render_template('remote/setup.html',
                           form_setup=form_setup,
                           display_order=display_order,
                           remote_hosts=remote_hosts,
                           host_auth=host_auth)
Example #13
0
    def post(self, unique_id, unit, channel, value):
        """Create a measurement"""
        if not utils_general.user_has_permission('edit_controllers'):
            abort(403)

        if channel < 0:
            abort(422, custom='channel must be >= 0')

        try:
            value = float(value)
        except:
            abort(422, custom='value does not represent a float')

        timestamp = None
        if ns_measurement.payload and 'timestamp' in ns_measurement.payload:
            ts = ns_measurement.payload["timestamp"]
            if ts is not None:
                if valid_date_str(ts):
                    timestamp = datetime.datetime.strptime(
                        ts, '%Y-%m-%dT%H:%M:%S.%fZ')
                else:
                    abort(422, custom='Invalid timestamp format. Must be formatted as %Y-%m-%dT%H:%M:%S.%fZ')

        try:
            return_ = write_influxdb_value(
                unique_id, unit, value, channel=channel, timestamp=timestamp)

            if return_:
                abort(500)
            else:
                return {'message': 'Success'}, 200
        except Exception:
            abort(500,
                  message='An exception occurred',
                  error=traceback.format_exc())
Example #14
0
def computer_command(action):
    """Execute one of several commands as root"""
    if not utils_general.user_has_permission('edit_settings'):
        return redirect(url_for('routes_general.home'))

    try:
        if action not in [
                'restart', 'shutdown', 'daemon_restart', 'frontend_reload'
        ]:
            flash("Unrecognized command: {action}".format(action=action),
                  "success")
            return redirect('/settings')
        cmd = '{path}/mycodo/scripts/mycodo_wrapper {action} 2>&1'.format(
            path=INSTALL_DIRECTORY, action=action)
        subprocess.Popen(cmd, shell=True)
        if action == 'restart':
            flash(gettext("System rebooting in 10 seconds"), "success")
        elif action == 'shutdown':
            flash(gettext("System shutting down in 10 seconds"), "success")
        elif action == 'daemon_restart':
            flash(gettext("Command to restart the daemon sent"), "success")
        elif action == 'frontend_reload':
            flash(gettext("Command to reload the frontend sent"), "success")
        return redirect('/settings')
    except Exception as e:
        logger.error("System command '{cmd}' raised and error: "
                     "{err}".format(cmd=action, err=e))
        flash(
            "System command '{cmd}' raised and error: "
            "{err}".format(cmd=action, err=e), "error")
        return redirect(url_for('routes_general.home'))
Example #15
0
    def get(self, unique_id):
        """Show the settings for an function"""
        if not utils_general.user_has_permission('view_settings'):
            abort(403)
        try:
            list_data = get_from_db(FunctionSchema, CustomController, unique_id=unique_id)

            function_channel_schema = FunctionChannelSchema()
            list_channels = return_list_of_dictionaries(
                function_channel_schema.dump(
                    FunctionChannel.query.filter_by(
                        function_id=unique_id).all(), many=True))

            measure_schema = DeviceMeasurementsSchema()
            list_measurements = return_list_of_dictionaries(
                measure_schema.dump(
                    DeviceMeasurements.query.filter_by(
                        device_id=unique_id).all(), many=True))

            return {'function settings': list_data,
                    'function channels': list_channels,
                    'device measurements': list_measurements}, 200
        except Exception:
            abort(500,
                  message='An exception occurred',
                  error=traceback.format_exc())
Example #16
0
    def get(self, unique_id):
        """Show the settings for an input."""
        if not utils_general.user_has_permission('view_settings'):
            abort(403)
        try:
            list_data = get_from_db(InputSchema, Input, unique_id=unique_id)

            measure_schema = InputChannelSchema()
            list_channels = return_list_of_dictionaries(
                measure_schema.dump(
                    InputChannel.query.filter_by(input_id=unique_id).all(),
                    many=True))

            measure_schema = DeviceMeasurementsSchema()
            list_measurements = return_list_of_dictionaries(
                measure_schema.dump(DeviceMeasurements.query.filter_by(
                    device_id=unique_id).join(DeviceMeasurements.conversion,
                                              isouter=True).all(),
                                    many=True))

            return {
                'input settings': list_data,
                'input channels': list_channels,
                'device measurements': list_measurements
            }, 200
        except Exception:
            abort(500,
                  message='An exception occurred',
                  error=traceback.format_exc())
Example #17
0
def page_dashboard_add():
    """Add a dashboard"""
    if not utils_general.user_has_permission('edit_controllers'):
        return redirect(url_for('routes_general.home'))
    dashboard_id = utils_dashboard.dashboard_add()
    return redirect(
        url_for('routes_dashboard.page_dashboard', dashboard_id=dashboard_id))
Example #18
0
    def get(self):
        """Show all output settings and statuses"""
        if not utils_general.user_has_permission('view_settings'):
            abort(403)
        try:
            list_data = get_from_db(OutputSchema, Output)
            list_channels = get_from_db(OutputChannelSchema, OutputChannel)
            states = get_all_output_states()

            # Change integer channel keys to strings (flask-restx limitation?)
            new_state_dict = {}
            for each_id in states:
                new_state_dict[each_id] = {}
                for each_channel in states[each_id]:
                    new_state_dict[each_id][str(
                        each_channel)] = states[each_id][each_channel]

            if list_data:
                return {
                    'output devices': list_data,
                    'output channels': list_channels,
                    'output states': new_state_dict
                }, 200
        except Exception:
            abort(500,
                  message='An exception occurred',
                  error=traceback.format_exc())
Example #19
0
def method_delete(method_id):
    """Delete a method"""
    action = '{action} {controller}'.format(
        action=TRANSLATIONS['delete']['title'],
        controller=gettext("Method"))

    if not utils_general.user_has_permission('edit_settings'):
        return redirect(url_for('routes_method.method_list'))

    try:
        MethodData.query.filter(
            MethodData.method_id == method_id).delete()
        MethodData.query.filter(
            MethodData.linked_method_id == method_id).delete()
        Method.query.filter(
            Method.unique_id == method_id).delete()
        display_order = csv_to_list_of_str(DisplayOrder.query.first().method)
        display_order.remove(method_id)
        DisplayOrder.query.first().method = list_to_csv(display_order)
        db.session.commit()
        flash("Success: {action}".format(action=action), "success")
    except Exception as except_msg:
        flash("Error: {action}: {err}".format(action=action,
                                              err=except_msg),
              "error")
    return redirect(url_for('routes_method.method_list'))
Example #20
0
def remote_setup():
    """Return pages for remote administration"""
    if not utils_general.user_has_permission('edit_settings'):
        return redirect(url_for('routes_general.home'))

    remote_hosts = Remote.query.all()
    display_order_unsplit = DisplayOrder.query.first().remote_host
    if display_order_unsplit:
        display_order = display_order_unsplit.split(",")
    else:
        display_order = []

    form_setup = forms_authentication.RemoteSetup()

    if request.method == 'POST':
        if form_setup.add.data:
            utils_remote_host.remote_host_add(form_setup,
                                              display_order)
        elif form_setup.delete.data:
            utils_remote_host.remote_host_del(form_setup)
        return redirect('/remote/setup')

    host_auth = {}
    for each_host in remote_hosts:
        headers = remote_log_in(
            each_host.host, each_host.username, each_host.password_hash)

        _, host_auth[each_host.host] = remote_host_page(
            each_host.host, headers, 'auth')

    return render_template('remote/setup.html',
                           form_setup=form_setup,
                           display_order=display_order,
                           remote_hosts=remote_hosts,
                           host_auth=host_auth)
Example #21
0
def remote_input():
    """Returns input information for remote administration"""
    if not utils_general.user_has_permission('edit_settings'):
        return redirect(url_for('routes_general.home'))

    remote_hosts = Remote.query.all()
    display_order_unsplit = DisplayOrder.query.first().remote_host
    if display_order_unsplit:
        display_order = display_order_unsplit.split(",")
    else:
        display_order = []

    host_auth = {}
    host_inputs = {}
    for each_host in remote_hosts:
        # Return input information about each host
        headers = remote_log_in(
            each_host.host, each_host.username, each_host.password_hash)

        _, host_inputs[each_host.host] = remote_host_page(
            each_host.host, headers, 'remote_get_inputs')

        host_inputs[each_host.host] = json.loads(host_inputs[each_host.host])

    return render_template('remote/input.html',
                           display_order=display_order,
                           remote_hosts=remote_hosts,
                           host_auth=host_auth,
                           host_inputs=host_inputs)
Example #22
0
def save_function_layout():
    """Save positions of functions"""
    if not utils_general.user_has_permission('edit_controllers'):
        return redirect(url_for('routes_general.home'))
    data = request.get_json()
    keys = ('id', 'y')
    for each_function in data:
        if all(k in each_function for k in keys):
            controller_type = determine_controller_type(each_function['id'])

            if controller_type == "Conditional":
                mod_device = Conditional.query.filter(
                    Conditional.unique_id == each_function['id']).first()
            elif controller_type == "PID":
                mod_device = PID.query.filter(
                    PID.unique_id == each_function['id']).first()
            elif controller_type == "Trigger":
                mod_device = Trigger.query.filter(
                    Trigger.unique_id == each_function['id']).first()
            elif controller_type == "Function":
                mod_device = Function.query.filter(
                    Function.unique_id == each_function['id']).first()
            elif controller_type == "Function_Custom":
                mod_device = CustomController.query.filter(
                    CustomController.unique_id == each_function['id']).first()
            else:
                logger.info("Could not find controller with ID {}".format(
                    each_function['id']))
                return "error"
            if mod_device:
                mod_device.position_y = each_function['y']
    db.session.commit()
    return "success"
Example #23
0
    def get(self, unique_id, unit, channel, past_seconds):
        """
        Return the last measurement found within a duration from the past to the present
        """
        if not utils_general.user_has_permission('view_settings'):
            abort(403)

        if unit not in add_custom_units(Unit.query.all()):
            abort(422, custom='Unit ID not found')
        if channel < 0:
            abort(422, custom='channel must be >= 0')
        if past_seconds < 1:
            abort(422, custom='past_seconds must be >= 1')

        try:
            return_ = read_influxdb_single(unique_id,
                                           unit,
                                           channel,
                                           duration_sec=past_seconds)
            if return_ and len(return_) == 2:
                return {'time': return_[0], 'value': return_[1]}, 200
            else:
                return return_, 200
        except Exception:
            abort(500,
                  message='An exception occurred',
                  error=traceback.format_exc())
Example #24
0
def output_mod(output_id, channel, state, output_type, amount):
    """ Manipulate output (using non-unique ID) """
    if not utils_general.user_has_permission('edit_controllers'):
        return 'Insufficient user permissions to manipulate outputs'

    if is_int(channel):
        # if an integer was returned
        output_channel = int(channel)
    else:
        # if a channel ID was returned
        channel_dev = db_retrieve_table(OutputChannel).filter(
            OutputChannel.unique_id == channel).first()
        if channel_dev:
            output_channel = channel_dev.channel
        else:
            return "Could not determine channel number from channel ID '{}'".format(
                channel)

    daemon = DaemonControl()
    if (state in ['on', 'off'] and str_is_float(amount) and
        ((output_type in ['sec', 'pwm', 'vol'] and float(amount) >= 0) or
         (output_type == 'value'))):
        out_status = daemon.output_on_off(output_id,
                                          state,
                                          output_type=output_type,
                                          amount=float(amount),
                                          output_channel=output_channel)
        if out_status[0]:
            return 'ERROR: {}'.format(out_status[1])
        else:
            return 'SUCCESS: {}'.format(out_status[1])
    else:
        return 'ERROR: unknown parameters: ' \
               'output_id: {}, channel: {}, state: {}, output_type: {}, amount: {}'.format(
                output_id, channel, state, output_type, amount)
Example #25
0
def computer_command(action):
    """Execute one of several commands as root"""
    if not utils_general.user_has_permission('edit_settings'):
        return redirect(url_for('routes_general.home'))

    try:
        if action not in ['restart', 'shutdown', 'daemon_restart', 'frontend_reload']:
            flash("Unrecognized command: {action}".format(
                action=action), "success")
            return redirect('/settings')
        cmd = '{path}/mycodo/scripts/mycodo_wrapper {action} 2>&1'.format(
                path=INSTALL_DIRECTORY, action=action)
        subprocess.Popen(cmd, shell=True)
        if action == 'restart':
            flash(gettext("System rebooting in 10 seconds"), "success")
        elif action == 'shutdown':
            flash(gettext("System shutting down in 10 seconds"), "success")
        elif action == 'daemon_restart':
            flash(gettext("Command to restart the daemon sent"), "success")
        elif action == 'frontend_reload':
            flash(gettext("Command to reload the frontend sent"), "success")
        return redirect('/settings')
    except Exception as e:
        logger.error("System command '{cmd}' raised and error: "
                     "{err}".format(cmd=action, err=e))
        flash("System command '{cmd}' raised and error: "
              "{err}".format(cmd=action, err=e), "error")
        return redirect(url_for('routes_general.home'))
Example #26
0
    def get(self, unique_id, unit, channel, past_seconds):
        """
        Return a list of measurements found within a duration from the past to the present
        """
        if not utils_general.user_has_permission('view_settings'):
            abort(403)

        if unit not in add_custom_units(Unit.query.all()):
            abort(422, custom='Unit ID not found')
        if channel < 0:
            abort(422, custom='channel must be >= 0')
        if past_seconds < 1:
            abort(422, custom='past_seconds must be >= 1')

        try:
            return_ = read_influxdb_list(unique_id,
                                         unit,
                                         channel,
                                         duration_sec=past_seconds)
            if return_ and len(return_) > 0:
                dict_return = {'measurements': []}
                for each_set in return_:
                    dict_return['measurements'].append({
                        'time': each_set[0],
                        'value': each_set[1]
                    })
                return dict_return, 200
            else:
                return return_, 200
        except Exception:
            abort(500,
                  message='An exception occurred',
                  error=traceback.format_exc())
Example #27
0
    def get(self, unique_id):
        """Show the settings and status for an output."""
        if not utils_general.user_has_permission('edit_controllers'):
            abort(403)

        try:
            list_data = get_from_db(OutputSchema, Output, unique_id=unique_id)

            output_channel_schema = OutputChannelSchema()
            list_channels = return_list_of_dictionaries(
                output_channel_schema.dump(
                    OutputChannel.query.filter_by(
                        output_id=unique_id).all(), many=True))

            states = get_all_output_states()

            # Change integer channel keys to strings (flask-restx limitation?)
            new_state_dict = {}
            for each_channel in states[unique_id]:
                new_state_dict[str(each_channel)] = states[unique_id][each_channel]

            return {'output device': list_data,
                    'output device channels': list_channels,
                    'output device channel states': new_state_dict}, 200
        except Exception:
            abort(500,
                  message='An exception occurred',
                  error=traceback.format_exc())
Example #28
0
    def get(self, unique_id):
        """Show the settings and status for an output"""
        if not utils_general.user_has_permission('edit_controllers'):
            abort(403)

        try:
            dict_data = get_from_db(OutputSchema, Output, unique_id=unique_id)

            measure_schema = DeviceMeasurementsSchema()
            list_data = return_list_of_dictionaries(
                measure_schema.dump(DeviceMeasurements.query.filter_by(
                    device_id=unique_id).all(),
                                    many=True))

            control = DaemonControl()
            output_state = control.output_state(unique_id)
            return {
                'output settings': dict_data,
                'output device measurements': list_data,
                'output state': output_state
            }, 200
        except Exception:
            abort(500,
                  message='An exception occurred',
                  error=traceback.format_exc())
Example #29
0
def output_mod(output_id, channel_id, state, output_type, amount):
    """ Manipulate output (using non-unique ID) """
    if not utils_general.user_has_permission('edit_controllers'):
        return 'Insufficient user permissions to manipulate outputs'

    if channel_id == '0':
        # some parts of pages don't have access to the channel ID and only know there is 1 channel
        channel = db_retrieve_table(OutputChannel).filter(and_(
            OutputChannel.output_id == output_id,
            OutputChannel.channel == 0)).first()
    else:
        channel = db_retrieve_table(OutputChannel, unique_id=channel_id)

    daemon = DaemonControl()
    if (state in ['on', 'off'] and output_type in ['sec', 'pwm', 'vol'] and
            (str_is_float(amount) and float(amount) >= 0)):
        out_status = daemon.output_on_off(
            output_id,
            state,
            output_type=output_type,
            amount=float(amount),
            output_channel=channel.channel)
        if out_status[0]:
            return 'ERROR: {}'.format(out_status[1])
        else:
            return 'SUCCESS: {}'.format(out_status[1])
Example #30
0
    def post(self, unique_id):
        """Change the state of an output"""
        if not utils_general.user_has_permission('edit_controllers'):
            abort(403)

        control = DaemonControl()

        state = None
        duration = None
        duty_cycle = None

        if ns_output.payload:
            if 'state' in ns_output.payload:
                state = ns_output.payload["state"]
                if state is not None:
                    try:
                        state = bool(state)
                    except Exception:
                        abort(422, message='state must represent a bool value')

            if 'duration' in ns_output.payload:
                duration = ns_output.payload["duration"]
                if duration is not None:
                    try:
                        duration = float(duration)
                    except Exception:
                        abort(422, message='duration does not represent a number')
                else:
                    duration = 0

            if 'duty_cycle' in ns_output.payload:
                duty_cycle = ns_output.payload["duty_cycle"]
                if duty_cycle is not None:
                    try:
                        duty_cycle = float(duty_cycle)
                        if duty_cycle < 0 or duty_cycle > 100:
                            abort(422, message='Required: 0 <= duty_cycle <= 100')
                    except Exception:
                        abort(422,
                              message='duty_cycle does not represent float value')

        try:
            if state is not None and duration is not None:
                return_ = control.output_on_off(
                    unique_id, state, amount=duration)
            elif state is not None:
                return_ = control.output_on_off(unique_id, state)
            elif duty_cycle is not None:
                return_ = control.output_duty_cycle(
                    unique_id, duty_cycle=duty_cycle)
            else:
                return {'message': 'Insufficient payload'}, 460

            return return_handler(return_)
        except Exception:
            abort(500,
                  message='An exception occurred',
                  error=traceback.format_exc())
Example #31
0
def settings_controller():
    """ Display controller settings """
    if not utils_general.user_has_permission('view_settings'):
        return redirect(url_for('routes_general.home'))

    form_controller = forms_settings.Controller()
    form_controller_delete = forms_settings.ControllerDel()

    # Get list of custom controllers
    excluded_files = ['__init__.py', '__pycache__']

    if request.method == 'POST':
        if not utils_general.user_has_permission('edit_controllers'):
            return redirect(url_for('routes_general.home'))

        if form_controller.import_controller_upload.data:
            utils_settings.settings_controller_import(form_controller)
        elif form_controller_delete.delete_controller.data:
            utils_settings.settings_controller_delete(form_controller_delete)

        return redirect(url_for('routes_settings.settings_controller'))

    dict_controllers = {}

    for each_file in os.listdir(PATH_CONTROLLERS_CUSTOM):
        if each_file not in excluded_files:
            try:
                full_path_file = os.path.join(PATH_CONTROLLERS_CUSTOM,
                                              each_file)
                controller_info = load_module_from_file(
                    full_path_file, 'controllers')
                dict_controllers[controller_info.CONTROLLER_INFORMATION[
                    'controller_name_unique']] = {}
                dict_controllers[controller_info.CONTROLLER_INFORMATION['controller_name_unique']]['controller_name'] = \
                    controller_info.CONTROLLER_INFORMATION['controller_name']
            except:
                pass

    # dict_controllers = parse_controller_information()

    return render_template('settings/controller.html',
                           dict_controllers=dict_controllers,
                           form_controller=form_controller,
                           form_controller_delete=form_controller_delete)
Example #32
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
        })
Example #33
0
def pid_mod_unique_id(unique_id, state):
    """ Manipulate output (using unique ID) """
    if not utils_general.user_has_permission('edit_controllers'):
        return 'Insufficient user permissions to manipulate PID'

    pid = PID.query.filter(PID.unique_id == unique_id).first()

    daemon = DaemonControl()
    if state == 'activate_pid':
        pid.is_activated = True
        pid.save()
        return_val, return_str = daemon.controller_activate(
            'PID', pid.unique_id)
        return return_str
    elif state == 'deactivate_pid':
        pid.is_activated = False
        pid.is_paused = False
        pid.is_held = False
        pid.save()
        return_val, return_str = daemon.controller_deactivate(
            'PID', pid.unique_id)
        return return_str
    elif state == 'pause_pid':
        pid.is_paused = True
        pid.save()
        if pid.is_activated:
            return_str = daemon.pid_pause(pid.unique_id)
        else:
            return_str = "PID Paused (Note: PID is not currently active)"
        return return_str
    elif state == 'hold_pid':
        pid.is_held = True
        pid.save()
        if pid.is_activated:
            return_str = daemon.pid_hold(pid.unique_id)
        else:
            return_str = "PID Held (Note: PID is not currently active)"
        return return_str
    elif state == 'resume_pid':
        pid.is_held = False
        pid.is_paused = False
        pid.save()
        if pid.is_activated:
            return_str = daemon.pid_resume(pid.unique_id)
        else:
            return_str = "PID Resumed (Note: PID is not currently active)"
        return return_str
    elif 'set_setpoint_pid' in state:
        pid.setpoint = state.split('|')[1]
        pid.save()
        if pid.is_activated:
            return_str = daemon.pid_set(pid.unique_id, 'setpoint',
                                        float(state.split('|')[1]))
        else:
            return_str = "PID Setpoint changed (Note: PID is not currently active)"
        return return_str
Example #34
0
def settings_users():
    """Display user settings."""
    if not utils_general.user_has_permission('view_settings'):
        return redirect(url_for('routes_general.home'))

    messages = {"success": [], "info": [], "warning": [], "error": []}

    misc = Misc.query.first()
    form_user = forms_settings.User()
    form_add_user = forms_settings.UserAdd()
    form_mod_user = forms_settings.UserMod()
    form_user_roles = forms_settings.UserRoles()

    if request.method == 'POST':
        if not utils_general.user_has_permission('edit_users'):
            return redirect(url_for('routes_general.home'))

        if form_add_user.user_add.data:
            utils_settings.user_add(form_add_user)
        elif form_user_roles.user_role_add.data:
            messages, page_refresh = utils_settings.user_roles(form_user_roles)

    for each_error in messages["error"]:
        flash(each_error, "error")
    for each_warn in messages["warning"]:
        flash(each_warn, "warning")
    for each_info in messages["info"]:
        flash(each_info, "info")
    for each_success in messages["success"]:
        flash(each_success, "success")

    users = User.query.all()
    user_roles = Role.query.all()

    return render_template('settings/users.html',
                           misc=misc,
                           themes=THEMES,
                           users=users,
                           user_roles=user_roles,
                           form_add_user=form_add_user,
                           form_mod_user=form_mod_user,
                           form_user=form_user,
                           form_user_roles=form_user_roles)
Example #35
0
def admin_statistics():
    """ Display collected statistics """
    if not utils_general.user_has_permission('view_stats'):
        return redirect(url_for('routes_general.home'))

    try:
        statistics = return_stat_file_dict(STATS_CSV)
    except IOError:
        statistics = {}
    return render_template('admin/statistics.html', statistics=statistics)
Example #36
0
def settings_alerts():
    """ Display alert settings """
    if not utils_general.user_has_permission('view_settings'):
        return redirect(url_for('routes_general.home'))

    smtp = SMTP.query.first()
    form_email_alert = forms_settings.SettingsEmail()

    if request.method == 'POST':
        if not utils_general.user_has_permission('edit_settings'):
            return redirect(url_for('routes_general.home'))

        form_name = request.form['form-name']
        if form_name == 'EmailAlert':
            utils_settings.settings_alert_mod(form_email_alert)
        return redirect(url_for('routes_settings.settings_alerts'))

    return render_template('settings/alerts.html',
                           smtp=smtp,
                           form_email_alert=form_email_alert)
Example #37
0
def admin_statistics():
    """ Display collected statistics """
    if not utils_general.user_has_permission('view_stats'):
        return redirect(url_for('routes_general.home'))

    try:
        statistics = return_stat_file_dict(STATS_CSV)
    except IOError:
        statistics = {}
    return render_template('admin/statistics.html',
                           statistics=statistics)
Example #38
0
def pid_mod_unique_id(unique_id, state):
    """ Manipulate output (using unique ID) """
    if not utils_general.user_has_permission('edit_controllers'):
        return 'Insufficient user permissions to manipulate PID'

    pid = PID.query.filter(PID.unique_id == unique_id).first()

    daemon = DaemonControl()
    if state == 'activate_pid':
        pid.is_activated = True
        pid.save()
        return_val, return_str = daemon.controller_activate('PID', pid.unique_id)
        return return_str
    elif state == 'deactivate_pid':
        pid.is_activated = False
        pid.is_paused = False
        pid.is_held = False
        pid.save()
        return_val, return_str = daemon.controller_deactivate('PID', pid.unique_id)
        return return_str
    elif state == 'pause_pid':
        pid.is_paused = True
        pid.save()
        if pid.is_activated:
            return_str = daemon.pid_pause(pid.unique_id)
        else:
            return_str = "PID Paused (Note: PID is not currently active)"
        return return_str
    elif state == 'hold_pid':
        pid.is_held = True
        pid.save()
        if pid.is_activated:
            return_str = daemon.pid_hold(pid.unique_id)
        else:
            return_str = "PID Held (Note: PID is not currently active)"
        return return_str
    elif state == 'resume_pid':
        pid.is_held = False
        pid.is_paused = False
        pid.save()
        if pid.is_activated:
            return_str = daemon.pid_resume(pid.unique_id)
        else:
            return_str = "PID Resumed (Note: PID is not currently active)"
        return return_str
    elif 'set_setpoint_pid' in state:
        pid.setpoint = state.split('|')[1]
        pid.save()
        if pid.is_activated:
            return_str = daemon.pid_set(pid.unique_id, 'setpoint', float(state.split('|')[1]))
        else:
            return_str = "PID Setpoint changed (Note: PID is not currently active)"
        return return_str
Example #39
0
def output_mod(output_id, state, out_type, amount):
    """ Manipulate output (using non-unique ID) """
    if not utils_general.user_has_permission('edit_controllers'):
        return 'Insufficient user permissions to manipulate outputs'

    daemon = DaemonControl()
    if (state in ['on', 'off'] and out_type == 'sec' and
            (str_is_float(amount) and float(amount) >= 0)):
        return daemon.output_on_off(output_id, state, float(amount))
    elif (state == 'on' and out_type in ['pwm', 'command_pwm'] and
              (str_is_float(amount) and float(amount) >= 0)):
        return daemon.output_on(output_id, duty_cycle=float(amount))
Example #40
0
def settings_general():
    """ Display general settings """
    if not utils_general.user_has_permission('view_settings'):
        return redirect(url_for('routes_general.home'))

    misc = Misc.query.first()
    form_settings_general = forms_settings.SettingsGeneral()

    languages_sorted = sorted(LANGUAGES.items(), key=operator.itemgetter(1))

    if request.method == 'POST':
        if not utils_general.user_has_permission('edit_settings'):
            return redirect(url_for('routes_general.home'))

        form_name = request.form['form-name']
        if form_name == 'General':
            utils_settings.settings_general_mod(form_settings_general)
        return redirect(url_for('routes_settings.settings_general'))

    return render_template('settings/general.html',
                           misc=misc,
                           languages=languages_sorted,
                           form_settings_general=form_settings_general)
Example #41
0
def settings_pi():
    """ Display general settings """
    if not utils_general.user_has_permission('view_settings'):
        return redirect(url_for('routes_general.home'))

    misc = Misc.query.first()
    form_settings_pi = forms_settings.SettingsPi()

    pi_settings = get_raspi_config_settings()

    # Determine what state pigpiod is currently in
    pigpiod_sample_rate = ''
    if os.path.exists('/etc/systemd/system/pigpiod_uninstalled.service'):
        pigpiod_sample_rate = 'uninstalled'
    elif os.path.exists('/etc/systemd/system/pigpiod_disabled.service'):
        pigpiod_sample_rate = 'disabled'
    elif os.path.exists('/etc/systemd/system/pigpiod_low.service'):
        pigpiod_sample_rate = 'low'
    elif os.path.exists('/etc/systemd/system/pigpiod_high.service'):
        pigpiod_sample_rate = 'high'
    elif os.path.exists('/etc/systemd/system/pigpiod.service'):
        pigpiod_sample_rate = 'low'

    if request.method == 'POST':
        if not utils_general.user_has_permission('edit_settings'):
            return redirect(url_for('routes_general.home'))

        form_name = request.form['form-name']
        if form_name == 'Pi':
            utils_settings.settings_pi_mod(form_settings_pi)
        return redirect(url_for('routes_settings.settings_pi'))

    return render_template('settings/pi.html',
                           misc=misc,
                           pi_settings=pi_settings,
                           pigpiod_sample_rate=pigpiod_sample_rate,
                           form_settings_pi=form_settings_pi)
Example #42
0
def settings_users():
    """ Display user settings """
    if not utils_general.user_has_permission('view_settings'):
        return redirect(url_for('routes_general.home'))

    users = User.query.all()
    user_roles = Role.query.all()
    form_add_user = forms_settings.UserAdd()
    form_mod_user = forms_settings.UserMod()
    form_user_roles = forms_settings.UserRoles()

    if request.method == 'POST':
        if not utils_general.user_has_permission('edit_users'):
            return redirect(url_for('routes_general.home'))

        if form_add_user.add_user.data:
            utils_settings.user_add(form_add_user)
        elif form_mod_user.delete.data:
            if utils_settings.user_del(form_mod_user) == 'logout':
                return redirect('/logout')
        elif form_mod_user.save.data:
            if utils_settings.user_mod(form_mod_user) == 'logout':
                return redirect('/logout')
        elif (form_user_roles.add_role.data or
                form_user_roles.save_role.data or
                form_user_roles.delete_role.data):
            utils_settings.user_roles(form_user_roles)
        return redirect(url_for('routes_settings.settings_users'))

    return render_template('settings/users.html',
                           themes=THEMES,
                           users=users,
                           user_roles=user_roles,
                           form_add_user=form_add_user,
                           form_mod_user=form_mod_user,
                           form_user_roles=form_user_roles)
Example #43
0
def settings_camera():
    """ Display camera settings """
    if not utils_general.user_has_permission('view_settings'):
        return redirect(url_for('routes_general.home'))

    form_camera = forms_settings.SettingsCamera()

    camera = Camera.query.all()
    output = Output.query.all()

    pi_camera_enabled = False
    try:
        if 'start_x=1' in open('/boot/config.txt').read():
            pi_camera_enabled = True
    except IOError as e:
        logger.error("Camera IOError raised in '/settings/camera' endpoint: "
                     "{err}".format(err=e))

    if request.method == 'POST':
        if not utils_general.user_has_permission('edit_settings'):
            return redirect(url_for('routes_general.home'))

        if form_camera.camera_add.data:
            utils_settings.camera_add(form_camera)
        elif form_camera.camera_mod.data:
            utils_settings.camera_mod(form_camera)
        elif form_camera.camera_del.data:
            utils_settings.camera_del(form_camera)
        return redirect(url_for('routes_settings.settings_camera'))

    return render_template('settings/camera.html',
                           camera=camera,
                           camera_libraries=CAMERA_LIBRARIES,
                           form_camera=form_camera,
                           pi_camera_enabled=pi_camera_enabled,
                           output=output)
Example #44
0
def admin_dependencies(device):
    """ Display Dependency page """
    form_dependencies = forms_dependencies.Dependencies()

    if device != '0':
        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

    dict_inputs = parse_input_information()

    list_dependencies = [
        dict_inputs,
        LCD_INFO,
        MATH_INFO,
        METHOD_INFO,
        OUTPUT_INFO,
        CALIBRATION_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

            # Determine if there are any unmet dependencies
            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:
            install_in_progress = True
            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)
Example #45
0
def admin_upgrade():
    """ Display any available upgrades and option to upgrade """
    if not utils_general.user_has_permission('edit_settings'):
        return redirect(url_for('routes_general.home'))

    if not internet():
        flash(gettext("Upgrade functionality is disabled because an internet "
                      "connection was unable to be detected"),
              "error")
        return render_template('admin/upgrade.html',
                               is_internet=False)

    # Read from the upgrade status file created by the upgrade script
    # to indicate if the upgrade is running.
    try:
        with open(UPGRADE_INIT_FILE) as f:
            upgrade = int(f.read(1))
    except IOError:
        try:
            with open(UPGRADE_INIT_FILE, 'w') as f:
                f.write('0')
        finally:
            upgrade = 0

    if upgrade:
        if upgrade == 2:
            flash(gettext("There was an error encountered during the upgrade"
                          " process. Check the upgrade log for details."),
                  "error")
        return render_template('admin/upgrade.html',
                               upgrade=upgrade)

    form_backup = forms_misc.Backup()
    form_upgrade = forms_misc.Upgrade()

    is_internet = True
    upgrade_available = False

    # Check for any new Mycodo releases on github
    releases = []
    try:
        current_maj_version = int(MYCODO_VERSION.split('.')[0])
        releases = github_releases(current_maj_version)
    except Exception as err:
        flash(gettext("Could not determine local mycodo version or "
                      "online release versions: {err}".format(err=err)),
              "error")
    if len(releases):
        current_latest_release = github_latest_release()
        current_latest_major_version = current_latest_release.split('.')[0]
        current_major_release = releases[0]
        current_releases = []
        releases_behind = None
        for index, each_release in enumerate(releases):
            if parse_version(each_release) >= parse_version(MYCODO_VERSION):
                current_releases.append(each_release)
            if parse_version(each_release) == parse_version(MYCODO_VERSION):
                releases_behind = index
        if (parse_version(releases[0]) > parse_version(MYCODO_VERSION) or
                parse_version(current_latest_release[0]) > parse_version(MYCODO_VERSION)):
            upgrade_available = True
    else:
        current_releases = []
        current_latest_release = '0.0.0'
        current_latest_major_version = '0'
        current_major_release = '0.0.0'
        releases_behind = 0

    # Update database to reflect the current upgrade status
    mod_misc = Misc.query.first()
    if mod_misc.mycodo_upgrade_available != upgrade_available:
        mod_misc.mycodo_upgrade_available = upgrade_available
        db.session.commit()

    def not_enough_space_upgrade():
        backup_size, free_before, free_after = can_perform_backup()
        if free_after / 1000000 < 50:
            flash(
                "A backup must be performed during an upgrade and there is "
                "not enough free space to perform a backup. A backup "
                "requires {size_bu:.1f} MB but there is only {size_free:.1f} "
                "MB available, which would leave {size_after:.1f} MB after "
                "the backup. If the free space after a backup is less than 50"
                " MB, the backup cannot proceed. Free up space by deleting "
                "current backups.".format(size_bu=backup_size / 1000000,
                                          size_free=free_before / 1000000,
                                          size_after=free_after / 1000000),
                'error')
            return True
        else:
            return False

    if request.method == 'POST':
        if (form_upgrade.upgrade.data and
                (upgrade_available or FORCE_UPGRADE_MASTER)):
            if not_enough_space_upgrade():
                pass
            elif FORCE_UPGRADE_MASTER:
                cmd = "{pth}/mycodo/scripts/mycodo_wrapper upgrade-master" \
                      " | ts '[%Y-%m-%d %H:%M:%S]'" \
                      " >> {log} 2>&1".format(pth=INSTALL_DIRECTORY,
                                              log=UPGRADE_LOG_FILE)
                subprocess.Popen(cmd, shell=True)

                upgrade = 1
                flash(gettext("The upgrade (from master branch) has started"), "success")
            else:
                cmd = "{pth}/mycodo/scripts/mycodo_wrapper upgrade" \
                      " | ts '[%Y-%m-%d %H:%M:%S]'" \
                      " >> {log} 2>&1".format(pth=INSTALL_DIRECTORY,
                                              log=UPGRADE_LOG_FILE)
                subprocess.Popen(cmd, shell=True)

                upgrade = 1
                mod_misc = Misc.query.first()
                mod_misc.mycodo_upgrade_available = False
                db.session.commit()
                flash(gettext("The upgrade has started"), "success")
        elif (form_upgrade.upgrade_next_major_version.data and
                upgrade_available):
            if not not_enough_space_upgrade():
                cmd = "{pth}/mycodo/scripts/mycodo_wrapper upgrade-release-major {ver}" \
                      " | ts '[%Y-%m-%d %H:%M:%S]'" \
                      " >> {log} 2>&1".format(pth=INSTALL_DIRECTORY,
                                              ver=current_latest_major_version,
                                              log=UPGRADE_LOG_FILE)
                subprocess.Popen(cmd, shell=True)

                upgrade = 1
                mod_misc = Misc.query.first()
                mod_misc.mycodo_upgrade_available = False
                db.session.commit()
            flash(gettext("The major version upgrade has started"), "success")
        else:
            flash(gettext("You cannot upgrade if an upgrade is not available"),
                  "error")

    return render_template('admin/upgrade.html',
                           final_releases=FINAL_RELEASES,
                           force_upgrade_master=FORCE_UPGRADE_MASTER,
                           form_backup=form_backup,
                           form_upgrade=form_upgrade,
                           current_release=MYCODO_VERSION,
                           current_releases=current_releases,
                           current_major_release=current_major_release,
                           current_latest_release=current_latest_release,
                           current_latest_major_version=current_latest_major_version,
                           releases_behind=releases_behind,
                           upgrade_available=upgrade_available,
                           upgrade=upgrade,
                           is_internet=is_internet)
Example #46
0
def admin_backup():
    """ Load the backup management page """
    if not utils_general.user_has_permission('edit_settings'):
        return redirect(url_for('routes_general.home'))

    form_backup = forms_misc.Backup()

    backup_dirs_tmp = []
    if not os.path.isdir('/var/Mycodo-backups'):
        flash("Error: Backup directory doesn't exist.", "error")
    else:
        backup_dirs_tmp = sorted(next(os.walk(BACKUP_PATH))[1])
        backup_dirs_tmp.reverse()

    backup_dirs = []
    full_paths = []
    for each_dir in backup_dirs_tmp:
        if each_dir.startswith("Mycodo-backup-"):
            full_path = os.path.join(BACKUP_PATH, each_dir)
            backup_dirs.append((each_dir, get_directory_size(full_path) / 1000000.0))
            full_paths.append(full_path)

    if request.method == 'POST':
        if form_backup.backup.data:
            backup_size, free_before, free_after = can_perform_backup()
            if free_after / 1000000 > 50:
                cmd = "{pth}/mycodo/scripts/mycodo_wrapper backup-create" \
                      " | ts '[%Y-%m-%d %H:%M:%S]'" \
                      " >> {log} 2>&1".format(pth=INSTALL_DIRECTORY,
                                              log=BACKUP_LOG_FILE)
                subprocess.Popen(cmd, shell=True)
                flash(gettext("Backup in progress"), "success")
            else:
                flash(
                    "Not enough free space to perform a backup. A backup "
                    "requires {size_bu:.1f} MB but there is only "
                    "{size_free:.1f} MB available, which would leave "
                    "{size_after:.1f} MB after the backup. If the free space "
                    "after a backup is less than 50 MB, the backup cannot "
                    "proceed. Free up space by deleting current "
                    "backups.".format(size_bu=backup_size / 1000000,
                                      size_free=free_before / 1000000,
                                      size_after=free_after / 1000000),
                    'error')

        elif form_backup.delete.data:
            cmd = "{pth}/mycodo/scripts/mycodo_wrapper backup-delete {dir}" \
                  " 2>&1".format(pth=INSTALL_DIRECTORY,
                                 dir=form_backup.selected_dir.data)
            subprocess.Popen(cmd, shell=True)
            flash(gettext("Deletion of backup in progress"),
                  "success")

        elif form_backup.restore.data:
            cmd = "{pth}/mycodo/scripts/mycodo_wrapper backup-restore {backup}" \
                  " | ts '[%Y-%m-%d %H:%M:%S]'" \
                  " >> {log} 2>&1".format(pth=INSTALL_DIRECTORY,
                                          backup=form_backup.full_path.data,
                                          log=RESTORE_LOG_FILE)
            subprocess.Popen(cmd, shell=True)
            flash(gettext("Restore in progress"),
                  "success")

    return render_template('admin/backup.html',
                           form_backup=form_backup,
                           backup_dirs=backup_dirs,
                           full_paths=full_paths)
Example #47
0
def settings_measurement():
    """ Display measurement settings """
    if not utils_general.user_has_permission('view_settings'):
        return redirect(url_for('routes_general.home'))

    measurement = Measurement.query.all()
    unit = Unit.query.all()
    conversion = Conversion.query.all()
    form_add_measurement = forms_settings.MeasurementAdd()
    form_mod_measurement = forms_settings.MeasurementMod()
    form_add_unit = forms_settings.UnitAdd()
    form_mod_unit = forms_settings.UnitMod()
    form_add_conversion = forms_settings.ConversionAdd()
    form_mod_conversion = forms_settings.ConversionMod()

    choices_units = utils_general.choices_units(unit)

    # Generate all measurement and units used
    dict_measurements = add_custom_measurements(measurement)
    dict_units = add_custom_units(unit)

    if request.method == 'POST':
        if not utils_general.user_has_permission('edit_controllers'):
            return redirect(url_for('routes_general.home'))

        if form_add_measurement.add_measurement.data:
            utils_settings.settings_measurement_add(form_add_measurement)
        elif form_mod_measurement.save_measurement.data:
            utils_settings.settings_measurement_mod(form_mod_measurement)
        elif form_mod_measurement.delete_measurement.data:
            utils_settings.settings_measurement_del(form_mod_measurement.measurement_id.data)

        elif form_add_unit.add_unit.data:
            utils_settings.settings_unit_add(form_add_unit)
        elif form_mod_unit.save_unit.data:
            utils_settings.settings_unit_mod(form_mod_unit)
        elif form_mod_unit.delete_unit.data:
            utils_settings.settings_unit_del(form_mod_unit.unit_id.data)

        elif form_add_conversion.add_conversion.data:
            utils_settings.settings_convert_add(form_add_conversion)
        elif form_mod_conversion.save_conversion.data:
            utils_settings.settings_convert_mod(form_mod_conversion)
        elif form_mod_conversion.delete_conversion.data:
            utils_settings.settings_convert_del(form_mod_conversion.conversion_id.data)

        return redirect(url_for('routes_settings.settings_measurement'))

    return render_template('settings/measurement.html',
                           dict_measurements=dict_measurements,
                           dict_units=dict_units,
                           choices_units=choices_units,
                           measurement=measurement,
                           unit=unit,
                           conversion=conversion,
                           form_add_measurement=form_add_measurement,
                           form_mod_measurement=form_mod_measurement,
                           form_add_unit=form_add_unit,
                           form_mod_unit=form_mod_unit,
                           form_add_conversion=form_add_conversion,
                           form_mod_conversion=form_mod_conversion)