Example #1
0
def page_relay():
    """ Display relay status and config """
    if not logged_in():
        return redirect(url_for('general_routes.home'))

    lcd = db_retrieve_table(
        current_app.config['MYCODO_DB_PATH'], LCD, entry='all')
    relay = db_retrieve_table(
        current_app.config['MYCODO_DB_PATH'], Relay, entry='all')
    relayconditional = db_retrieve_table(
        current_app.config['MYCODO_DB_PATH'], RelayConditional, entry='all')
    users = db_retrieve_table(
        current_app.config['USER_DB_PATH'], Users, entry='all')

    display_order_unsplit = db_retrieve_table(
        current_app.config['MYCODO_DB_PATH'], DisplayOrder, entry='first').relay
    if display_order_unsplit:
        display_order = display_order_unsplit.split(",")
    else:
        display_order = []

    form_add_relay = flaskforms.AddRelay()
    form_del_relay = flaskforms.DelRelay()
    form_mod_relay = flaskforms.ModRelay()
    form_order_relay = flaskforms.OrderRelay()
    form_relay_on_off = flaskforms.RelayOnOff()
    form_add_relay_cond = flaskforms.AddRelayConditional()
    form_mod_relay_cond = flaskforms.ModRelayConditional()

    if request.method == 'POST':
        form_name = request.form['form-name']
        if form_name == 'RelayOnOff':
            flaskutils.relay_on_off(form_relay_on_off)
        elif form_name == 'addRelay':
            flaskutils.relay_add(form_add_relay, display_order)
        elif form_name == 'modRelay':
            flaskutils.relay_mod(form_mod_relay)
        elif form_name == 'delRelay':
            flaskutils.relay_del(form_del_relay, display_order)
        elif form_name == 'orderRelay':
            flaskutils.relay_reorder(form_order_relay, display_order)
        elif form_name == 'addRelayConditional':
            flaskutils.relay_conditional_add(form_add_relay_cond)
        elif form_name == 'modRelayConditional':
            flaskutils.relay_conditional_mod(form_mod_relay_cond)
        return redirect('/relay')

    return render_template('pages/relay.html',
                           lcd=lcd,
                           relay=relay,
                           relayconditional=relayconditional,
                           users=users,
                           displayOrder=display_order,
                           form_order_relay=form_order_relay,
                           form_add_relay=form_add_relay,
                           form_mod_relay=form_mod_relay,
                           form_del_relay=form_del_relay,
                           form_relay_on_off=form_relay_on_off,
                           form_add_relay_cond=form_add_relay_cond,
                           form_mod_relay_cond=form_mod_relay_cond)
Example #2
0
def page_lcd():
    """ Display LCD output settings """
    if not logged_in():
        return redirect(url_for('general_routes.home'))

    lcd = db_retrieve_table(
        current_app.config['MYCODO_DB_PATH'], LCD, entry='all')
    pid = db_retrieve_table(
        current_app.config['MYCODO_DB_PATH'], PID, entry='all')
    relay = db_retrieve_table(
        current_app.config['MYCODO_DB_PATH'], Relay, entry='all')
    sensor = db_retrieve_table(
        current_app.config['MYCODO_DB_PATH'], Sensor, entry='all')

    display_order_unsplit = db_retrieve_table(
        current_app.config['MYCODO_DB_PATH'], DisplayOrder, entry='first').lcd
    if display_order_unsplit:
        display_order = display_order_unsplit.split(",")
    else:
        display_order = []

    form_activate_lcd = flaskforms.ActivateLCD()
    form_add_lcd = flaskforms.AddLCD()
    form_deactivate_lcd = flaskforms.DeactivateLCD()
    form_del_lcd = flaskforms.DelLCD()
    form_mod_lcd = flaskforms.ModLCD()
    form_order_lcd = flaskforms.OrderLCD()
    form_reset_flashing_lcd = flaskforms.ResetFlashingLCD()

    if request.method == 'POST':
        form_name = request.form['form-name']
        if form_name == 'orderLCD':
            flaskutils.lcd_reorder(form_order_lcd, display_order)
        elif form_name == 'addLCD':
            flaskutils.lcd_add(form_add_lcd, display_order)
        elif form_name == 'modLCD':
            flaskutils.lcd_mod(form_mod_lcd)
        elif form_name == 'delLCD':
            flaskutils.lcd_del(form_del_lcd, display_order)
        elif form_name == 'activateLCD':
            flaskutils.lcd_activate(form_activate_lcd)
        elif form_name == 'deactivateLCD':
            flaskutils.lcd_deactivate(form_deactivate_lcd)
        elif form_name == 'resetFlashingLCD':
            flaskutils.lcd_reset_flashing(form_reset_flashing_lcd)
        return redirect('/lcd')

    return render_template('pages/lcd.html',
                           lcd=lcd,
                           pid=pid,
                           relay=relay,
                           sensor=sensor,
                           displayOrder=display_order,
                           form_order_lcd=form_order_lcd,
                           form_add_lcd=form_add_lcd,
                           form_mod_lcd=form_mod_lcd,
                           form_del_lcd=form_del_lcd,
                           form_activate_lcd=form_activate_lcd,
                           form_deactivate_lcd=form_deactivate_lcd,
                           form_reset_flashing_lcd=form_reset_flashing_lcd)
Example #3
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 #4
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 #5
0
def page_graph_async():
    """ Generate graphs using asynchronous data retrieval """
    if not logged_in():
        return redirect(url_for('general_routes.home'))

    sensor = db_retrieve_table(
        current_app.config['MYCODO_DB_PATH'], Sensor, entry='all')
    sensor_choices = flaskutils.choices_sensors(sensor)
    sensor_choices_split = OrderedDict()
    for key, _ in sensor_choices.iteritems():
        order = key.split(",")
        # Separate sensor IDs and measurement types
        sensor_choices_split.update({order[0]: order[1]})

    selected_id = None
    selected_measure = None
    if request.method == 'POST':
        selected_id = request.form['selected_measure'].split(",")[0]
        selected_measure = request.form['selected_measure'].split(",")[1]

    return render_template('pages/graph-async.html',
                           sensor=sensor,
                           sensor_choices=sensor_choices,
                           sensor_choices_split=sensor_choices_split,
                           selected_id=selected_id,
                           selected_measure=selected_measure)
Example #6
0
def settings_users():
    """ Display user settings """
    if not logged_in():
        return redirect(url_for('general_routes.home'))

    if session['user_group'] == 'guest':
        flaskutils.deny_guest_user()
        return redirect(url_for('general_routes.home'))

    users = db_retrieve_table(
        current_app.config['USER_DB_PATH'], Users, entry='all')
    form_add_user = flaskforms.AddUser()
    form_mod_user = flaskforms.ModUser()
    form_del_user = flaskforms.DelUser()

    if request.method == 'POST':
        form_name = request.form['form-name']
        if form_name == 'addUser':
            flaskutils.user_add(form_add_user)
        elif form_name == 'delUser':
            if flaskutils.user_del(form_del_user) == 'logout':
                return redirect('/logout')
        elif form_name == 'modUser':
            if flaskutils.user_mod(form_mod_user) == 'logout':
                return redirect('/logout')
        return redirect('/settings/users')

    return render_template('settings/users.html',
                           users=users,
                           form_add_user=form_add_user,
                           form_mod_user=form_mod_user,
                           form_del_user=form_del_user)
Example #7
0
def parse_custom_option_values_function_channels_json(
        controllers, dict_controller=None, key_name='custom_channel_options'):
    # Check if controllers is iterable or a single controller
    try:
        _ = iter(controllers)
    except TypeError:
        iter_controller = [controllers]  # Not iterable
    else:
        iter_controller = controllers  # iterable

    custom_options_values = {}
    for each_controller in iter_controller:
        if each_controller.function_id not in custom_options_values:
            custom_options_values[each_controller.function_id] = {}
        if each_controller.custom_options:
            custom_options_values[each_controller.function_id][
                each_controller.channel] = json.loads(
                    each_controller.custom_options)

        if dict_controller:
            # Set default values if option not saved in database entry
            function = db_retrieve_table(CustomController,
                                         unique_id=each_controller.function_id)
            if not function:
                continue
            try:
                function.unique_id
            except:
                continue
            dev_name = function.device

            if dev_name in dict_controller and key_name in dict_controller[
                    dev_name]:
                dict_custom_options = dict_controller[dev_name][key_name]
            else:
                dict_custom_options = {}
            for each_option in dict_custom_options:
                if 'id' in each_option and 'default_value' in each_option:
                    if each_controller.channel not in custom_options_values[
                            each_controller.function_id]:
                        custom_options_values[each_controller.function_id][
                            each_controller.channel] = {}
                    if each_option['id'] not in custom_options_values[
                            each_controller.function_id][
                                each_controller.channel]:
                        # If a select type has cast_value set, cast the value as that type
                        if each_option[
                                'type'] == 'select' and 'cast_value' in each_option:
                            if each_option['cast_value'] == 'integer':
                                each_option['default_value'] = int(
                                    each_option['default_value'])
                            elif each_option['cast_value'] == 'float':
                                each_option['default_value'] = float(
                                    each_option['default_value'])
                        custom_options_values[each_controller.function_id][
                            each_controller.channel][each_option[
                                'id']] = each_option['default_value']

    return custom_options_values
Example #8
0
def page_timer():
    """ Display Timer settings """
    if not logged_in():
        return redirect(url_for('general_routes.home'))

    timer = db_retrieve_table(
        current_app.config['MYCODO_DB_PATH'], Timer, entry='all')
    relay = db_retrieve_table(
        current_app.config['MYCODO_DB_PATH'], Relay, entry='all')
    relay_choices = flaskutils.choices_id_name(relay)

    display_order_unsplit = db_retrieve_table(
        current_app.config['MYCODO_DB_PATH'], DisplayOrder, entry='first').timer
    if display_order_unsplit:
        display_order = display_order_unsplit.split(",")
    else:
        display_order = []

    form_timer = flaskforms.Timer()

    if request.method == 'POST':
        form_name = request.form['form-name']
        if form_name == 'addTimer':
            flaskutils.timer_add(form_timer,
                                 request.form['timer_type'],
                                 display_order)
        elif form_name == 'modTimer':
            if form_timer.timerDel.data:
                flaskutils.timer_del(form_timer, display_order)
            elif (form_timer.orderTimerUp.data or
                    form_timer.orderTimerDown.data):
                flaskutils.timer_reorder(form_timer, display_order)
            elif form_timer.activate.data:
                flaskutils.timer_activate(form_timer)
            elif form_timer.deactivate.data:
                flaskutils.timer_deactivate(form_timer)
            elif form_timer.timerMod.data:
                flaskutils.timer_mod(form_timer)
        return redirect('/timer')

    return render_template('pages/timer.html',
                           timer=timer,
                           displayOrder=display_order,
                           relay_choices=relay_choices,
                           form_timer=form_timer)
Example #9
0
 def get_locale():
     misc = db_retrieve_table(app.config['MYCODO_DB_PATH'],
                              Misc,
                              entry='first')
     if misc.language != '':
         for key, _ in LANGUAGES.iteritems():
             if key == misc.language:
                 return key
     return request.accept_languages.best_match(LANGUAGES.keys())
Example #10
0
def page_export():
    """
    Export measurement data in CSV format
    """
    if not logged_in():
        return redirect(url_for('general_routes.home'))

    export_options = flaskforms.ExportOptions()
    relay = db_retrieve_table(
        current_app.config['MYCODO_DB_PATH'], Relay, entry='all')
    sensor = db_retrieve_table(
        current_app.config['MYCODO_DB_PATH'], Sensor, entry='all')
    relay_choices = flaskutils.choices_id_name(relay)
    sensor_choices = flaskutils.choices_sensors(sensor)

    if request.method == 'POST':
        start_time = export_options.date_range.data.split(' - ')[0]
        start_seconds = int(time.mktime(
            time.strptime(start_time, '%m/%d/%Y %H:%M')))
        end_time = export_options.date_range.data.split(' - ')[1]
        end_seconds = int(time.mktime(
            time.strptime(end_time, '%m/%d/%Y %H:%M')))
        url = '/export_data/{meas}/{id}/{start}/{end}'.format(
            meas=export_options.measurement.data.split(',')[1],
            id=export_options.measurement.data.split(',')[0],
            start=start_seconds, end=end_seconds)
        return redirect(url)

    # Generate start end end times for date/time picker
    end_picker = datetime.datetime.now().strftime('%m/%d/%Y %H:%M')
    start_picker = datetime.datetime.now() - datetime.timedelta(hours=6)
    start_picker = start_picker.strftime('%m/%d/%Y %H:%M')

    return render_template('tools/export.html',
                           start_picker=start_picker,
                           end_picker=end_picker,
                           exportOptions=export_options,
                           relay_choices=relay_choices,
                           sensor_choices=sensor_choices)
Example #11
0
def page_live():
    """ Page of recent and updating sensor data """
    if not logged_in():
        return redirect(url_for('general_routes.home'))

    # Retrieve tables for the data displayed on the live page
    pid = db_retrieve_table(
        current_app.config['MYCODO_DB_PATH'], PID, entry='all')
    relay = db_retrieve_table(
        current_app.config['MYCODO_DB_PATH'], Relay, entry='all')
    sensor = db_retrieve_table(
        current_app.config['MYCODO_DB_PATH'], Sensor, entry='all')
    timer = db_retrieve_table(
        current_app.config['MYCODO_DB_PATH'], Timer, entry='all')

    # Retrieve the display order of the controllers
    pid_display_order_unsplit = db_retrieve_table(
        current_app.config['MYCODO_DB_PATH'], DisplayOrder, entry='first').pid
    if pid_display_order_unsplit:
        pid_display_order = pid_display_order_unsplit.split(",")
    else:
        pid_display_order = []

    sensor_display_order_unsplit = db_retrieve_table(
        current_app.config['MYCODO_DB_PATH'], DisplayOrder, entry='first').sensor
    if sensor_display_order_unsplit:
        sensor_display_order = sensor_display_order_unsplit.split(",")
    else:
        sensor_display_order = []

    # Filter only activated sensors
    sensor_order_sorted = []
    for each_sensor_order in sensor_display_order:
        for each_sensor in sensor:
            if (each_sensor_order == each_sensor.id and
                    each_sensor.activated):
                sensor_order_sorted.append(each_sensor.id)

    # Retrieve only parent method columns
    method = db_retrieve_table(
        current_app.config['MYCODO_DB_PATH'], Method)
    method = method.filter(
        Method.method_order == 0).all()

    return render_template('pages/live.html',
                           method=method,
                           pid=pid,
                           relay=relay,
                           sensor=sensor,
                           timer=timer,
                           pidDisplayOrder=pid_display_order,
                           sensorDisplayOrderSorted=sensor_order_sorted)
Example #12
0
def register_extensions(_app, config):
    """ register extensions to the app """
    _app.jinja_env.add_extension('jinja2.ext.do')  # Global values in jinja

    # create the databases if needed
    create_dbs(None, create_all=True, config=config, exit_when_done=False)

    # attach influx db
    influx_db.init_app(_app)

    # Check user option to force all web connections to use SSL
    misc = db_retrieve_table(_app.config['MYCODO_DB_PATH'],
                             Misc,
                             entry='first')
    if misc.force_https:
        SSLify(_app)
Example #13
0
def camera_del(form_camera):
    messages = {"success": [], "info": [], "warning": [], "error": []}

    camera = db_retrieve_table(Camera, unique_id=form_camera.camera_id.data)
    if camera.timelapse_started:
        messages["error"].append(
            "Cannot delete camera if a time-lapse is currently "
            "active. Stop the time-lapse and try again.")

    if not messages["error"]:
        try:
            delete_entry_with_id(Camera, form_camera.camera_id.data)
            messages["success"].append("Camera deleted")
        except Exception as except_msg:
            messages["error"].append(except_msg)

    return messages
Example #14
0
def camera_timelapse_video(form_camera):
    action = "Generate Timelapse Video"
    error = []

    if not os.path.exists("/usr/bin/ffmpeg"):
        error.append(
            "ffmpeg not found. Install with 'sudo apt install ffmpeg'")

    if not error:
        try:
            camera = db_retrieve_table(Camera,
                                       unique_id=form_camera.camera_id.data)
            camera_path = assure_path_exists(
                os.path.join(PATH_CAMERAS,
                             '{uid}'.format(uid=camera.unique_id)))
            timelapse_path = assure_path_exists(
                os.path.join(camera_path, 'timelapse'))
            video_path = assure_path_exists(
                os.path.join(camera_path, 'timelapse_video'))
            timestamp = datetime.datetime.now().strftime('%Y-%m-%d_%H-%M-%S')
            path_file = os.path.join(
                video_path, "Video_{name}_{ts}.mp4".format(
                    name=form_camera.timelapse_image_set.data, ts=timestamp))

            cmd =  "/usr/bin/ffmpeg " \
                   "-f image2 " \
                   "-r {fps} " \
                   "-i {path}/{seq}-%05d.jpg " \
                   "-vcodec {codec} " \
                   "-y {save}".format(
                        seq=form_camera.timelapse_image_set.data,
                        fps=form_camera.timelapse_fps.data,
                        path=timelapse_path,
                        codec=form_camera.timelapse_codec.data,
                        save=path_file)
            subprocess.Popen(cmd, shell=True)
            flash(
                "The time-lapse video is being generated in the background with the command:\n"
                "{}".format(cmd), "success")
            flash("The video will be saved at "
                  "{}".format(path_file), "success")
        except Exception as except_msg:
            error.append(except_msg)

    flash_success_errors(error, action, url_for('routes_page.page_camera'))
Example #15
0
def camera_del(form_camera):
    action = '{action} {controller}'.format(action=gettext("Delete"),
                                            controller=gettext("Camera"))
    error = []

    camera = db_retrieve_table(Camera, device_id=form_camera.camera_id.data)
    if camera.timelapse_started:
        error.append("Cannot delete camera if a time-lapse is currently "
                     "using it. Stop the time-lapse and try again.")

    if not error:
        try:
            delete_entry_with_id(Camera, int(form_camera.camera_id.data))
        except Exception as except_msg:
            error.append(except_msg)

    flash_success_errors(error, action,
                         url_for('routes_settings.settings_camera'))
Example #16
0
def method_list():
    """ List all methods on one page with a graph for each """
    if not logged_in():
        return redirect(url_for('general_routes.home'))

    form_create_method = flaskforms.CreateMethod()

    # TODO: Move to Flask-SQLAlchemy. This creates errors in the HTTP log: "SQLite objects created in a thread can only be used in that same thread"
    method = db_retrieve_table(current_app.config['MYCODO_DB_PATH'], Method)

    method_all = method.filter(Method.method_order > 0)
    method_all = method_all.filter(Method.relay_id == None).all()
    method = method.filter(Method.method_order == 0).all()

    return render_template('pages/method-list.html',
                           method=method,
                           method_all=method_all,
                           form_create_method=form_create_method)
Example #17
0
def camera_del(form_camera):
    action = '{action} {controller}'.format(
        action=TRANSLATIONS['delete']['title'],
        controller=TRANSLATIONS['camera']['title'])
    error = []

    camera = db_retrieve_table(Camera, unique_id=form_camera.camera_id.data)
    if camera.timelapse_started:
        error.append("Cannot delete camera if a time-lapse is currently "
                     "using it. Stop the time-lapse and try again.")

    if not error:
        try:
            delete_entry_with_id(Camera, form_camera.camera_id.data)
        except Exception as except_msg:
            error.append(except_msg)

    flash_success_errors(error, action, url_for('routes_page.page_camera'))
Example #18
0
def settings_camera():
    """ Display camera settings """
    if not logged_in():
        return redirect(url_for('general_routes.home'))

    camera = db_retrieve_table(
        current_app.config['MYCODO_DB_PATH'], CameraStill, entry='first')
    form_settings_camera = flaskforms.SettingsCamera()

    if request.method == 'POST':
        form_name = request.form['form-name']
        if form_name == 'Camera':
            flaskutils.settings_camera_mod(form_settings_camera)
        return redirect('/settings/camera')

    return render_template('settings/camera.html',
                           camera=camera,
                           form_settings_camera=form_settings_camera)
Example #19
0
def test_add_sensor_logged_in_as_admin(_, testapp, user_db):
    """ Verifies behavior of these endpoints for a logged in admin user """
    # Create admin user and log in
    admin_user = create_user(user_db, 'admin', 'name_admin', 'secret_pass')
    login_user(testapp, admin_user.user_name, 'secret_pass')

    response = add_sensor(testapp)

    # Verify success message flashed
    assert "RPi Sensor with ID" in response
    assert "successfully added" in response

    # Verify data was entered into the database
    sensor = db_retrieve_table(current_app.config['MYCODO_DB_PATH'],
                               Sensor,
                               entry='all')
    for each_sensor in sensor:
        assert 'RPi' in each_sensor.name, "Sensor name doesn't match: {}".format(
            each_sensor.name)
Example #20
0
def authenticate_cookies(db_path, users):
    """Check for cookies to authenticate Login"""
    cookie_username = request.cookies.get('user_name')
    cookie_password_hash = request.cookies.get('user_pass_hash')
    if cookie_username is not None:
        user = db_retrieve_table(db_path, users)
        user = user.filter(Users.user_name == cookie_username).first()

        if user is None:
            return False
        elif cookie_password_hash == user.user_password_hash:
            session['logged_in'] = True
            session['user_group'] = user.user_restriction
            session['user_name'] = user.user_name
            session['user_theme'] = user.user_theme
            return True
        else:
            failed_login()
    return False
Example #21
0
def check_database_version_issue():
    alembic_version = db_retrieve_table(current_app.config['MYCODO_DB_PATH'],
                                        AlembicVersion,
                                        entry='all')
    if len(alembic_version) > 1:
        flash(
            "A check of your database indicates there is an issue with your"
            " database version number. This issue first appeared in early "
            "4.1.x versions of Mycodo and has since been resolved. However,"
            " even though things may seem okay, this issue prevents your "
            "database from being upgraded properly. Therefore, if you "
            "continue to use Mycodo without regenerating your database, you"
            " will assuredly experience issues. To resolve this issue, move"
            " your mycodo.db from ~/Mycodo/databases/mycodo.db to a "
            "different location (or delete it) and a new database will be "
            "generated in its place. You will need to configure Mycodo from"
            " scratch, but this is the only way to ensure your database is "
            "able to be upgraded when the time comes. Sorry for the "
            "inconvenience.", "error")
Example #22
0
def camera_timelapse_video(form_camera):
    messages = {"success": [], "info": [], "warning": [], "error": []}

    if not os.path.exists("/usr/bin/ffmpeg"):
        messages["error"].append(
            "ffmpeg not found. Install with 'sudo apt install ffmpeg'")

    if not messages["error"]:
        try:
            camera = db_retrieve_table(Camera,
                                       unique_id=form_camera.camera_id.data)
            camera_path = assure_path_exists(
                os.path.join(PATH_CAMERAS,
                             '{uid}'.format(uid=camera.unique_id)))
            timelapse_path = assure_path_exists(
                os.path.join(camera_path, 'timelapse'))
            video_path = assure_path_exists(
                os.path.join(camera_path, 'timelapse_video'))
            timestamp = datetime.datetime.now().strftime('%Y-%m-%d_%H-%M-%S')
            path_file = os.path.join(
                video_path, "Video_{name}_{ts}.mp4".format(
                    name=form_camera.timelapse_image_set.data, ts=timestamp))

            cmd =  "/usr/bin/ffmpeg " \
                   "-f image2 " \
                   "-r {fps} " \
                   "-i {path}/{seq}-%05d.jpg " \
                   "-vcodec {codec} " \
                   "-y {save}".format(
                        seq=form_camera.timelapse_image_set.data,
                        fps=form_camera.timelapse_fps.data,
                        path=timelapse_path,
                        codec=form_camera.timelapse_codec.data,
                        save=path_file)
            subprocess.Popen(cmd, shell=True)
            messages["success"].append(
                "The time-lapse video is being generated in the background with the command: {}."
                " The video will be saved at {}".format(cmd, path_file))
        except Exception as except_msg:
            messages["error"].append(except_msg)

    return messages
Example #23
0
def settings_general():
    """ Display general settings """
    if not logged_in():
        return redirect(url_for('general_routes.home'))

    misc = db_retrieve_table(
        current_app.config['MYCODO_DB_PATH'], Misc, entry='first')
    form_settings_general = flaskforms.SettingsGeneral()

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

    if request.method == 'POST':
        form_name = request.form['form-name']
        if form_name == 'General':
            flaskutils.settings_general_mod(form_settings_general)
        return redirect('/settings/general')

    return render_template('settings/general.html',
                           misc=misc,
                           languages=languages_sorted,
                           form_settings_general=form_settings_general)
Example #24
0
def settings_alerts():
    """ Display alert settings """
    if not logged_in():
        return redirect(url_for('general_routes.home'))

    if session['user_group'] == 'guest':
        flaskutils.deny_guest_user()
        return redirect('/settings')

    smtp = db_retrieve_table(
        current_app.config['MYCODO_DB_PATH'], SMTP, entry='first')
    form_email_alert = flaskforms.EmailAlert()

    if request.method == 'POST':
        form_name = request.form['form-name']
        # Update smtp settings table in mycodo SQL database
        if form_name == 'EmailAlert':
            flaskutils.settings_alert_mod(form_email_alert)
        return redirect('/settings/alerts')

    return render_template('settings/alerts.html',
                           smtp=smtp,
                           form_email_alert=form_email_alert)
Example #25
0
def do_login():
    """Authenticate users of the web-UI"""
    if not admin_exists():
        return redirect('/create_admin')

    if logged_in():
        flash(gettext("Cannot access login page if you're already logged in"),
              "error")
        return redirect(url_for('general_routes.home'))

    form = flaskforms.Login()
    form_notice = flaskforms.InstallNotice()

    misc = db_retrieve_table(current_app.config['MYCODO_DB_PATH'],
                             Misc,
                             entry='first')
    dismiss_notification = misc.dismiss_notification
    stats_opt_out = misc.stats_opt_out

    # Check if the user is banned from logging in (too many incorrect attempts)
    if banned_from_login():
        flash(
            gettext(
                "Too many failed login attempts. Please wait %(min)s "
                "minutes before attempting to log in again",
                min=(int(LOGIN_BAN_SECONDS - session['ban_time_left']) / 60) +
                1), "info")
    else:
        if request.method == 'POST':
            form_name = request.form['form-name']
            if form_name == 'acknowledge':
                try:
                    with session_scope(current_app.config['MYCODO_DB_PATH']
                                       ) as db_session:
                        mod_misc = db_session.query(Misc).first()
                        mod_misc.dismiss_notification = 1
                        db_session.commit()
                except Exception as except_msg:
                    flash(
                        gettext(
                            "Acknowledgement unable to be saved: "
                            "%(err)s",
                            err=except_msg), "error")
            elif form_name == 'login' and form.validate_on_submit():
                with session_scope(
                        current_app.config['USER_DB_PATH']) as new_session:
                    user = new_session.query(Users).filter(
                        Users.user_name == form.username.data).first()
                    new_session.expunge_all()
                    new_session.close()
                if not user:
                    login_log(
                        form.username.data, 'NA',
                        request.environ.get('REMOTE_ADDR', 'unknown address'),
                        'NOUSER')
                    failed_login()
                elif Users().check_password(
                        form.password.data,
                        user.user_password_hash) == user.user_password_hash:
                    login_log(
                        user.user_name, user.user_restriction,
                        request.environ.get('REMOTE_ADDR', 'unknown address'),
                        'LOGIN')
                    session['logged_in'] = True
                    session['user_group'] = user.user_restriction
                    session['user_name'] = user.user_name
                    session['user_theme'] = user.user_theme
                    if form.remember.data:
                        response = make_response(redirect('/'))
                        expire_date = datetime.datetime.now()
                        expire_date = expire_date + datetime.timedelta(days=90)
                        response.set_cookie('user_name',
                                            user.user_name,
                                            expires=expire_date)
                        response.set_cookie('user_pass_hash',
                                            user.user_password_hash,
                                            expires=expire_date)
                        return response
                    return redirect(url_for('general_routes.home'))
                else:
                    login_log(
                        user.user_name, user.user_restriction,
                        request.environ.get('REMOTE_ADDR', 'unknown address'),
                        'FAIL')
                    failed_login()
            else:
                login_log(
                    form.username.data, 'NA',
                    request.environ.get('REMOTE_ADDR', 'unknown address'),
                    'FAIL')
                failed_login()

            return redirect('/login')

    return render_template('login.html',
                           form=form,
                           formNotice=form_notice,
                           dismiss_notification=dismiss_notification,
                           stats_opt_out=stats_opt_out)
Example #26
0
def page_sensor():
    """ Display sensor settings """
    if not logged_in():
        return redirect(url_for('general_routes.home'))

    lcd = db_retrieve_table(
        current_app.config['MYCODO_DB_PATH'], LCD, entry='all')
    pid = db_retrieve_table(
        current_app.config['MYCODO_DB_PATH'], PID, entry='all')
    relay = db_retrieve_table(
        current_app.config['MYCODO_DB_PATH'], Relay, entry='all')
    sensor = db_retrieve_table(
        current_app.config['MYCODO_DB_PATH'], Sensor, entry='all')
    sensor_conditional = db_retrieve_table(
        current_app.config['MYCODO_DB_PATH'], SensorConditional, entry='all')
    users = db_retrieve_table(
        current_app.config['USER_DB_PATH'], Users, entry='all')

    display_order_unsplit = db_retrieve_table(
        current_app.config['MYCODO_DB_PATH'], DisplayOrder, entry='first').sensor
    if display_order_unsplit:
        display_order = display_order_unsplit.split(",")
    else:
        display_order = []

    form_add_sensor = flaskforms.AddSensor()
    form_mod_sensor = flaskforms.ModSensor()
    form_mod_sensor_cond = flaskforms.ModSensorConditional()

    # Create list of file names from the sensor_options directory
    # Used in generating the correct options for each sensor/device
    sensor_template_list = []
    sensor_path = "{path}/mycodo/mycodo_flask/templates/pages/sensor_options/".format(
        path=INSTALL_DIRECTORY)
    for (_, _, file_names) in os.walk(sensor_path):
        sensor_template_list.extend(file_names)
        break
    sensor_templates = []
    for each_file_name in sensor_template_list:
        sensor_templates.append(each_file_name.split(".")[0])

    if request.method == 'POST':
        form_name = request.form['form-name']
        if form_name == 'addSensor':
            flaskutils.sensor_add(form_add_sensor, display_order)
        elif form_name == 'modSensor':
            if form_mod_sensor.modSensorSubmit.data:
                flaskutils.sensor_mod(form_mod_sensor)
            elif form_mod_sensor.delSensorSubmit.data:
                flaskutils.sensor_del(form_mod_sensor, display_order)
            elif (form_mod_sensor.orderSensorUp.data or
                    form_mod_sensor.orderSensorDown.data):
                flaskutils.sensor_reorder(form_mod_sensor, display_order)
            elif form_mod_sensor.activateSensorSubmit.data:
                flaskutils.sensor_activate(form_mod_sensor)
            elif form_mod_sensor.deactivateSensorSubmit.data:
                flaskutils.sensor_deactivate(form_mod_sensor)
            elif form_mod_sensor.sensorCondAddSubmit.data:
                flaskutils.sensor_conditional_add(form_mod_sensor)
        elif form_name == 'modSensorConditional':
            flaskutils.sensor_conditional_mod(form_mod_sensor_cond)
        return redirect('/sensor')

    return render_template('pages/sensor.html',
                           lcd=lcd,
                           pid=pid,
                           relay=relay,
                           sensor=sensor,
                           sensor_conditional=sensor_conditional,
                           sensor_templates=sensor_templates,
                           users=users,
                           displayOrder=display_order,
                           form_add_sensor=form_add_sensor,
                           form_mod_sensor=form_mod_sensor,
                           form_mod_sensor_cond=form_mod_sensor_cond)
Example #27
0
def page_camera():
    """
    Page to start/stop video stream or time-lapse, or capture a still image.
    Displays most recent still image and time-lapse image.
    """
    if not logged_in():
        return redirect(url_for('general_routes.home'))

    form_camera = flaskforms.Camera()

    camera_enabled = False
    try:
        if 'start_x=1' in open('/boot/config.txt').read():
            camera_enabled = True
        else:
            flash(gettext("Camera support doesn't appear to be enabled. "
                          "Please enable it with 'sudo raspi-config'"),
                  "error")
    except IOError as e:
        logger.error("Camera IOError raised in '/camera' endpoint: "
                     "{err}".format(err=e))

    # Check if a video stream is active
    stream_locked = os.path.isfile(LOCK_FILE_STREAM)
    if stream_locked and not CameraStream().is_running():
        os.remove(LOCK_FILE_STREAM)
    stream_locked = os.path.isfile(LOCK_FILE_STREAM)

    if request.method == 'POST':
        form_name = request.form['form-name']
        if session['user_group'] == 'guest':
            flaskutils.deny_guest_user()
            return redirect('/camera')
        elif form_name == 'camera':
            if form_camera.Still.data:
                if not stream_locked:
                    try:
                        if CameraStream().is_running():
                            CameraStream().terminate_controller()  # Stop camera stream
                            time.sleep(2)
                        camera = db_retrieve_table(
                            current_app.config['MYCODO_DB_PATH'],
                            CameraStill, entry='first')
                        camera_record('photo', camera)
                    except Exception as msg:
                        flash("Camera Error: {}".format(msg), "error")
                else:
                    flash(gettext("Cannot capture still if stream is active. "
                                  "If it is not active, delete %(file)s.",
                                  file=LOCK_FILE_STREAM),
                          "error")

            elif form_camera.StartTimelapse.data:
                if not stream_locked:
                    # Create lock file and file with time-lapse parameters
                    open(LOCK_FILE_TIMELAPSE, 'a')

                    # Save time-lapse parameters to a csv file to resume
                    # if there is a power outage or reboot.
                    now = time.time()
                    timestamp = datetime.datetime.now().strftime(
                        '%Y-%m-%d_%H-%M-%S')
                    uid_gid = pwd.getpwnam('mycodo').pw_uid
                    timelapse_data = [
                        ['start_time', timestamp],
                        ['end_time', now + float(form_camera.TimelapseRunTime.data)],
                        ['interval', form_camera.TimelapseInterval.data],
                        ['next_capture', now],
                        ['capture_number', 0]]
                    with open(FILE_TIMELAPSE_PARAM, 'w') as time_lapse_file:
                        write_csv = csv.writer(time_lapse_file)
                        for row in timelapse_data:
                            write_csv.writerow(row)
                    os.chown(FILE_TIMELAPSE_PARAM, uid_gid, uid_gid)
                    os.chmod(FILE_TIMELAPSE_PARAM, 0664)
                else:
                    flash(gettext("Cannot start time-lapse if a video stream "
                                  "is active. If it is not active, delete "
                                  "%(file)s.", file=LOCK_FILE_STREAM),
                          "error")

            elif form_camera.StopTimelapse.data:
                try:
                    os.remove(FILE_TIMELAPSE_PARAM)
                    os.remove(LOCK_FILE_TIMELAPSE)
                except IOError as e:
                    logger.error("Camera IOError raised in '/camera' "
                                 "endpoint: {err}".format(err=e))

            elif form_camera.StartStream.data:
                if not is_time_lapse_locked():
                    open(LOCK_FILE_STREAM, 'a')
                    stream_locked = True
                else:
                    flash(gettext("Cannot start stream if a time-lapse is "
                                  "active. If not active, delete %(file)s.",
                                  file=LOCK_FILE_TIMELAPSE),
                          "error")

            elif form_camera.StopStream.data:
                if CameraStream().is_running():
                    CameraStream().terminate()
                if os.path.isfile(LOCK_FILE_STREAM):
                    os.remove(LOCK_FILE_STREAM)
                stream_locked = False

    # Get the full path of latest still image
    try:
        latest_still_img_full_path = max(glob.iglob(
            '{path}/camera-stills/*.jpg'.format(path=INSTALL_DIRECTORY)),
            key=os.path.getmtime)
        ts = os.path.getmtime(latest_still_img_full_path)
        latest_still_img_ts = datetime.datetime.fromtimestamp(ts).strftime("%c")
        latest_still_img = os.path.basename(latest_still_img_full_path)
    except Exception as e:
        logger.error(
            "Exception raised in '/camera' endpoint: {err}".format(err=e))
        latest_still_img_ts = None
        latest_still_img = None

    # Get the full path of latest timelapse image
    try:
        latest_time_lapse_img_full_path = max(glob.iglob(
            '{path}/camera-timelapse/*.jpg'.format(path=INSTALL_DIRECTORY)),
            key=os.path.getmtime)
        ts = os.path.getmtime(latest_time_lapse_img_full_path)
        latest_time_lapse_img_ts = datetime.datetime.fromtimestamp(ts).strftime("%c")
        latest_time_lapse_img = os.path.basename(
            latest_time_lapse_img_full_path)
    except Exception as e:
        logger.error(
            "Exception raised in '/camera' endpoint: {err}".format(err=e))
        latest_time_lapse_img_ts = None
        latest_time_lapse_img = None

    # If time-lapse active, retrieve parameters for display
    dict_time_lapse = {}
    time_now = datetime.datetime.now().strftime('%c')
    if (os.path.isfile(FILE_TIMELAPSE_PARAM) and
            os.path.isfile(LOCK_FILE_TIMELAPSE)):
        with open(FILE_TIMELAPSE_PARAM, mode='r') as infile:
            reader = csv.reader(infile)
            dict_time_lapse = OrderedDict((row[0], row[1]) for row in reader)
        dict_time_lapse['start_time'] = datetime.datetime.strptime(
            dict_time_lapse['start_time'], "%Y-%m-%d_%H-%M-%S")
        dict_time_lapse['start_time'] = dict_time_lapse['start_time'].strftime('%c')
        dict_time_lapse['end_time'] = datetime.datetime.fromtimestamp(
            float(dict_time_lapse['end_time'])).strftime('%c')
        dict_time_lapse['next_capture'] = datetime.datetime.fromtimestamp(
            float(dict_time_lapse['next_capture'])).strftime('%c')

    return render_template('pages/camera.html',
                           camera_enabled=camera_enabled,
                           form_camera=form_camera,
                           latest_still_img_ts=latest_still_img_ts,
                           latest_still_img=latest_still_img,
                           latest_time_lapse_img_ts=latest_time_lapse_img_ts,
                           latest_time_lapse_img=latest_time_lapse_img,
                           stream_locked=stream_locked,
                           time_lapse_locked=is_time_lapse_locked(),
                           time_now=time_now,
                           tl_parameters_dict=dict_time_lapse)
Example #28
0
def page_usage():
    """ Display relay usage (duration and energy usage/cost) """
    if not logged_in():
        return redirect(url_for('general_routes.home'))

    misc = db_retrieve_table(
        current_app.config['MYCODO_DB_PATH'], Misc, entry='first')
    relay = db_retrieve_table(
        current_app.config['MYCODO_DB_PATH'], Relay, entry='all')

    display_order_unsplit = db_retrieve_table(
        current_app.config['MYCODO_DB_PATH'], DisplayOrder, entry='first').relay
    if display_order_unsplit:
        display_order = display_order_unsplit.split(",")
    else:
        display_order = []

    # Calculate the number of seconds since the (n)th day of tyhe month
    # Enables usage/cost assessments to align with a power bill cycle
    now = datetime.date.today()
    past_month_seconds = 0
    day = misc.relay_stats_dayofmonth
    if 4 <= day <= 20 or 24 <= day <= 30:
        date_suffix = 'th'
    else:
        date_suffix = ['st', 'nd', 'rd'][day % 10 - 1]
    if misc.relay_stats_dayofmonth == datetime.datetime.today().day:
        dt_now = datetime.datetime.now()
        past_month_seconds = (dt_now - dt_now.replace(
            hour=0, minute=0, second=0, microsecond=0)).total_seconds()
    elif misc.relay_stats_dayofmonth > datetime.datetime.today().day:
        first_day = now.replace(day=1)
        last_month = first_day - datetime.timedelta(days=1)
        past_month = last_month.replace(day=misc.relay_stats_dayofmonth)
        past_month_seconds = (now - past_month).total_seconds()
    elif misc.relay_stats_dayofmonth < datetime.datetime.today().day:
        past_month = now.replace(day=misc.relay_stats_dayofmonth)
        past_month_seconds = (now - past_month).total_seconds()

    # Calculate relay on duration for different time periods
    relay_each_duration = {}
    relay_sum_duration = dict.fromkeys(
        ['1d', '1w', '1m', '1m-date', '1y'], 0)
    relay_sum_kwh = dict.fromkeys(
        ['1d', '1w', '1m', '1m-date', '1y'], 0)
    for each_relay in relay:
        relay_each_duration[each_relay.id] = {}
        relay_each_duration[each_relay.id]['1d'] = sum_relay_usage(
            each_relay.id, 86400) / 3600
        relay_each_duration[each_relay.id]['1w'] = sum_relay_usage(
            each_relay.id, 604800) / 3600
        relay_each_duration[each_relay.id]['1m'] = sum_relay_usage(
            each_relay.id, 2629743) / 3600
        relay_each_duration[each_relay.id]['1m-date'] = sum_relay_usage(
            each_relay.id, int(past_month_seconds)) / 3600
        relay_each_duration[each_relay.id]['1y'] = sum_relay_usage(
            each_relay.id, 31556926) / 3600
        relay_sum_duration['1d'] += relay_each_duration[each_relay.id]['1d']
        relay_sum_duration['1w'] += relay_each_duration[each_relay.id]['1w']
        relay_sum_duration['1m'] += relay_each_duration[each_relay.id]['1m']
        relay_sum_duration['1m-date'] += relay_each_duration[each_relay.id]['1m-date']
        relay_sum_duration['1y'] += relay_each_duration[each_relay.id]['1y']
        relay_sum_kwh['1d'] += (
            misc.relay_stats_volts * each_relay.amps *
            relay_each_duration[each_relay.id]['1d'] / 1000)
        relay_sum_kwh['1w'] += (
            misc.relay_stats_volts * each_relay.amps *
            relay_each_duration[each_relay.id]['1w'] / 1000)
        relay_sum_kwh['1m'] += (
            misc.relay_stats_volts * each_relay.amps *
            relay_each_duration[each_relay.id]['1m'] / 1000)
        relay_sum_kwh['1m-date'] += (
            misc.relay_stats_volts * each_relay.amps *
            relay_each_duration[each_relay.id]['1m-date'] / 1000)
        relay_sum_kwh['1y'] += (
            misc.relay_stats_volts * each_relay.amps *
            relay_each_duration[each_relay.id]['1y'] / 1000)

    return render_template('tools/usage.html',
                           display_order=display_order,
                           misc=misc,
                           relay=relay,
                           relay_each_duration=relay_each_duration,
                           relay_sum_duration=relay_sum_duration,
                           relay_sum_kwh=relay_sum_kwh,
                           date_suffix=date_suffix)
Example #29
0
def method_data(method_type, method_id):
    """
    Returns options for a particular method
    This includes sets of (time, setpoint) data.
    """
    logger.debug('called method_data(method_type={type}, '
                 'method_id={id})'.format(type=method_type, id=method_id))
    if not logged_in():
        return redirect(url_for('general_routes.home'))

    method = db_retrieve_table(current_app.config['MYCODO_DB_PATH'], Method)

    # First method column with general information about method
    method_key = method.filter(Method.method_id == method_id)
    method_key = method_key.filter(Method.method_order == 0).first()

    # User-edited lines of each method
    method = method.filter(Method.method_id == method_id)
    method = method.filter(Method.method_order > 0)
    method = method.filter(Method.relay_id == None)
    method = method.order_by(Method.method_order.asc()).all()

    method_list = []
    if method_key.method_type == "Date":
        for each_method in method:
            if each_method.end_setpoint == None:
                end_setpoint = each_method.start_setpoint
            else:
                end_setpoint = each_method.end_setpoint

            start_time = datetime.datetime.strptime(each_method.start_time,
                                                    '%Y-%m-%d %H:%M:%S')
            end_time = datetime.datetime.strptime(each_method.end_time,
                                                  '%Y-%m-%d %H:%M:%S')

            is_dst = time.daylight and time.localtime().tm_isdst > 0
            utc_offset_ms = (time.altzone if is_dst else time.timezone)
            method_list.append([
                (int(start_time.strftime("%s")) - utc_offset_ms) * 1000,
                each_method.start_setpoint
            ])
            method_list.append([
                (int(end_time.strftime("%s")) - utc_offset_ms) * 1000,
                end_setpoint
            ])
            method_list.append([
                (int(start_time.strftime("%s")) - utc_offset_ms) * 1000, None
            ])

    elif method_key.method_type == "Daily":
        for each_method in method:
            if each_method.end_setpoint is None:
                end_setpoint = each_method.start_setpoint
            else:
                end_setpoint = each_method.end_setpoint
            method_list.append([
                get_sec(each_method.start_time) * 1000,
                each_method.start_setpoint
            ])
            method_list.append(
                [get_sec(each_method.end_time) * 1000, end_setpoint])
            method_list.append([get_sec(each_method.start_time) * 1000, None])

    elif method_key.method_type == "DailyBezier":
        points_x = 700
        seconds_in_day = 60 * 60 * 24
        P0 = (method_key.x0, method_key.y0)
        P1 = (method_key.x1, method_key.y1)
        P2 = (method_key.x2, method_key.y2)
        P3 = (method_key.x3, method_key.y3)
        for n in range(points_x):
            percent = n / float(points_x)
            second_of_day = percent * seconds_in_day
            y = bezier_curve_y_out(method_key.shift_angle, P0, P1, P2, P3,
                                   second_of_day)
            method_list.append([percent * seconds_in_day * 1000, y])

    elif method_key.method_type == "DailySine":
        points_x = 700
        seconds_in_day = 60 * 60 * 24
        for n in range(points_x):
            percent = n / float(points_x)
            angle = n / float(points_x) * 360
            y = sine_wave_y_out(method_key.amplitude, method_key.frequency,
                                method_key.shift_angle, method_key.shift_y,
                                angle)
            method_list.append([percent * seconds_in_day * 1000, y])

    elif method_key.method_type == "Duration":
        first_entry = True
        start_duration = 0
        end_duration = 0
        for each_method in method:
            if each_method.end_setpoint is None:
                end_setpoint = each_method.start_setpoint
            else:
                end_setpoint = each_method.end_setpoint
            if first_entry:
                method_list.append([0, each_method.start_setpoint])
                method_list.append([each_method.duration_sec, end_setpoint])
                start_duration += each_method.duration_sec
                first_entry = False
            else:
                end_duration = start_duration + each_method.duration_sec

                method_list.append(
                    [start_duration, each_method.start_setpoint])
                method_list.append([end_duration, end_setpoint])

                start_duration += each_method.duration_sec

    return jsonify(method_list)
Example #30
0
def method_builder(method_type, method_id):
    """
    Page to edit the details of each method
    This includes the (time, setpoint) data sets
    """
    logger.debug('called method_builder(method_type={type}, '
                 'method_id={id})'.format(type=method_type, id=method_id))
    if not logged_in():
        return redirect(url_for('general_routes.home'))

    # Used in software tests to verify function is executing as admin
    if method_type == '1':
        return 'admin logged in'

    if method_type in [
            'Date', 'Duration', 'Daily', 'DailySine', 'DailyBezier', '0'
    ]:
        form_create_method = flaskforms.CreateMethod()
        form_add_method = flaskforms.AddMethod()
        form_mod_method = flaskforms.ModMethod()

        # Create new method
        if method_type == '0':
            random_id = ''.join([
                random.choice(string.ascii_letters + string.digits)
                for _ in xrange(8)
            ])
            method_id = random_id
            method_type = form_create_method.method_type.data
            form_fail = flaskutils.method_create(form_create_method, method_id)
            if not form_fail:
                flash(
                    gettext("New Method successfully created. You may now "
                            "add time points"), "success")
                return redirect('/method-build/{}/{}'.format(
                    method_type, method_id))
            else:
                flash(gettext("Could not create method"), "error")

        method = db_retrieve_table(current_app.config['MYCODO_DB_PATH'],
                                   Method)

        # The single table entry that holds the method type information
        method_key = method.filter(Method.method_id == method_id)
        method_key = method_key.filter(Method.method_order == 0).first()

        # The table entries with time, setpoint, and relay data, sorted by order
        method_list = method.filter(Method.method_order > 0)
        method_list = method_list.order_by(Method.method_order.asc()).all()

        last_end_time = ''
        last_setpoint = ''
        if method_type in ['Date', 'Daily']:
            last_method = method.filter(
                Method.method_id == method_key.method_id)
            last_method = last_method.filter(Method.method_order > 0)
            last_method = last_method.filter(Method.relay_id == None)
            last_method = last_method.order_by(
                Method.method_order.desc()).first()

            # Get last entry end time and setpoint to populate the form
            if last_method is None:
                last_end_time = ''
                last_setpoint = ''
            else:
                last_end_time = last_method.end_time
                if last_method.end_setpoint is not None:
                    last_setpoint = last_method.end_setpoint
                else:
                    last_setpoint = last_method.start_setpoint

        # method = db_retrieve_table(
        #     current_app.config['MYCODO_DB_PATH'], Method)
        relay = db_retrieve_table(current_app.config['MYCODO_DB_PATH'],
                                  Relay,
                                  entry='all')

        if request.method == 'POST':
            form_name = request.form['form-name']
            if form_name == 'addMethod':
                form_fail = flaskutils.method_add(form_add_method, method)
            elif form_name in ['modMethod', 'renameMethod']:
                form_fail = flaskutils.method_mod(form_mod_method, method)
            if (form_name in ['addMethod', 'modMethod', 'renameMethod']
                    and not form_fail):
                return redirect('/method-build/{}/{}'.format(
                    method_type, method_id))

        return render_template('pages/method-build.html',
                               method=method,
                               relay=relay,
                               method_key=method_key,
                               method_list=method_list,
                               method_id=method_id,
                               method_type=method_type,
                               last_end_time=last_end_time,
                               last_setpoint=last_setpoint,
                               form_create_method=form_create_method,
                               form_add_method=form_add_method,
                               form_mod_method=form_mod_method)

    return redirect('/method')