コード例 #1
0
    def __init__(self, ready, unique_id, testing=False):
        threading.Thread.__init__(self)
        super(CustomModule, self).__init__(ready,
                                           unique_id=unique_id,
                                           name=__name__)

        self.unique_id = unique_id
        self.log_level_debug = None
        self.timer_loop = time.time()

        self.control = DaemonControl()

        # Initialize custom options
        self.period = None
        self.start_offset = None
        self.select_measurement = None
        self.max_measure_age = None

        # Set custom options
        custom_function = db_retrieve_table_daemon(CustomController,
                                                   unique_id=unique_id)
        self.setup_custom_options(FUNCTION_INFORMATION['custom_options'],
                                  custom_function)
コード例 #2
0
ファイル: function_actions.py プロジェクト: stardawg/Mycodo
def action_setpoint_pid(cond_action, message):
    control = DaemonControl()
    pid = db_retrieve_table_daemon(PID,
                                   unique_id=cond_action.do_unique_id,
                                   entry='first')
    message += " Set Setpoint of PID {unique_id} ({id}, {name}).".format(
        unique_id=cond_action.do_unique_id, id=pid.id, name=pid.name)
    if pid.is_activated:
        setpoint_pid = threading.Thread(target=control.pid_set,
                                        args=(
                                            pid.unique_id,
                                            'setpoint',
                                            float(
                                                cond_action.do_action_string),
                                        ))
        setpoint_pid.start()
    else:
        with session_scope(MYCODO_DB_PATH) as new_session:
            mod_pid = new_session.query(PID).filter(
                PID.unique_id == cond_action.do_unique_id).first()
            mod_pid.setpoint = float(cond_action.do_action_string)
            new_session.commit()
    return message
コード例 #3
0
ファイル: routes_general.py プロジェクト: donpesce/Mycodo
def gpio_state_unique_id(unique_id):
    """Return the GPIO state, for dashboard output """
    output = Output.query.filter(
                Output.unique_id == unique_id).first()
    daemon_control = DaemonControl()
    GPIO.setmode(GPIO.BCM)
    GPIO.setwarnings(False)

    if output.relay_type == 'wired' and output.pin and -1 < output.pin < 40:
        GPIO.setup(output.pin, GPIO.OUT)
        if GPIO.input(output.pin) == output.trigger:
            state = 'on'
        else:
            state = 'off'
    elif (output.relay_type in ['command', 'command_pwm'] or
            (output.relay_type in ['pwm', 'wireless_433MHz_pi_switch'] and
             output.pin and
             -1 < output.pin < 40)):
        state = daemon_control.relay_state(output.id)
    else:
        state = None

    return jsonify(state)
コード例 #4
0
ファイル: routes_general.py プロジェクト: phaseiced/Mycodo
def output_mod(output_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'

    daemon = DaemonControl()
    if (state in ['on', 'off'] and output_type in ['sec', '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))
        if out_status[0]:
            return 'ERROR: {}'.format(out_status[1])
        else:
            return 'SUCCESS: {}'.format(out_status[1])

    elif (state == 'on' and output_type in outputs_pwm() and
            (str_is_float(amount) and float(amount) >= 0)):
        out_status = daemon.output_on(
            output_id, output_type=output_type, duty_cycle=float(amount))
        if out_status[0]:
            return 'ERROR: {}'.format(out_status[1])
        else:
            return 'SUCCESS: {}'.format(out_status[1])
コード例 #5
0
ファイル: routes_general.py プロジェクト: donpesce/Mycodo
def gpio_state():
    """Return the GPIO state, for output page status"""
    output = Output.query.all()
    daemon_control = DaemonControl()
    state = {}
    GPIO.setmode(GPIO.BCM)
    GPIO.setwarnings(False)
    for each_output in output:
        if each_output.relay_type == 'wired' and each_output.pin and -1 < each_output.pin < 40:
            GPIO.setup(each_output.pin, GPIO.OUT)
            if GPIO.input(each_output.pin) == each_output.trigger:
                state[each_output.id] = 'on'
            else:
                state[each_output.id] = 'off'
        elif (each_output.relay_type in ['command', 'command_pwm'] or
                (each_output.relay_type in ['pwm', 'wireless_433MHz_pi_switch'] and
                 each_output.pin and
                 -1 < each_output.pin < 40)):
            state[each_output.id] = daemon_control.relay_state(each_output.id)
        else:
            state[each_output.id] = None

    return jsonify(state)
コード例 #6
0
def action_deactivate_controller(cond_action, message):
    control = DaemonControl()
    (controller_type,
     controller_object,
     controller_entry) = which_controller(
        cond_action.do_unique_id)
    message += " Deactivate Controller {unique_id} ({id}, {name}).".format(
        unique_id=cond_action.do_unique_id,
        id=controller_entry.id,
        name=controller_entry.name)
    if not controller_entry.is_activated:
        message += " Notice: Controller is already inactive!"
    else:
        with session_scope(MYCODO_DB_PATH) as new_session:
            mod_cont = new_session.query(controller_object).filter(
                controller_object.unique_id == cond_action.do_unique_id).first()
            mod_cont.is_activated = False
            new_session.commit()
        deactivate_controller = threading.Thread(
            target=control.controller_deactivate,
            args=(cond_action.do_unique_id,))
        deactivate_controller.start()
    return message
コード例 #7
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())
コード例 #8
0
    def __init__(self):
        threading.Thread.__init__(self)

        self.logger = logging.getLogger("mycodo.conditional")

        self.running = False
        self.thread_startup_timer = timeit.default_timer()
        self.thread_shutdown_timer = 0
        self.pause_loop = False
        self.verify_pause_loop = True
        self.control = DaemonControl()

        self.is_activated = {}
        self.period = {}
        self.timer = {}

        self.smtp_max_count = db_retrieve_table_daemon(
            SMTP, entry='first').hourly_max
        self.email_count = 0
        self.allowed_to_send_notice = True
        self.smtp_wait_timer = {}

        self.setup_conditionals()
コード例 #9
0
    def __init__(self, function, testing=False):
        super(CustomModule, self).__init__(function,
                                           testing=testing,
                                           name=__name__)

        self.timer_loop = time.time()

        self.control = DaemonControl()

        # Initialize custom options
        self.period = None
        self.start_offset = None
        self.select_measurement = None
        self.max_measure_age = None

        # Set custom options
        custom_function = db_retrieve_table_daemon(CustomController,
                                                   unique_id=self.unique_id)
        self.setup_custom_options(FUNCTION_INFORMATION['custom_options'],
                                  custom_function)

        if not testing:
            self.initialize_variables()
コード例 #10
0
    def __init__(self, ready, unique_id):
        threading.Thread.__init__(self)
        super(TriggerController, self).__init__(ready, unique_id=unique_id, name=__name__)

        self.unique_id = unique_id
        self.sample_rate = None

        self.control = DaemonControl()
        
        self.pause_loop = False
        self.verify_pause_loop = True
        self.trigger = None
        self.trigger_type = None
        self.trigger_name = None
        self.is_activated = None
        self.log_level_debug = None
        self.smtp_max_count = None
        self.email_count = None
        self.allowed_to_send_notice = None
        self.smtp_wait_timer = None
        self.timer_period = None
        self.period = None
        self.smtp_wait_timer = None
        self.timer_start_time = None
        self.timer_end_time = None
        self.unique_id_1 = None
        self.unique_id_2 = None
        self.trigger_actions_at_period = None
        self.trigger_actions_at_start = None
        self.method_start_time = None
        self.method_end_time = None
        self.method_start_act = None

        # Infrared remote input
        self.lirc = None
        self.program = None
        self.word = None
コード例 #11
0
ファイル: bang_bang.py プロジェクト: zacky131/Mycodo
    def __init__(self, ready, unique_id, testing=False):
        threading.Thread.__init__(self)
        super(CustomModule, self).__init__(ready,
                                           unique_id=unique_id,
                                           name=__name__)

        self.unique_id = unique_id
        self.log_level_debug = None
        self.control_variable = None
        self.timestamp = None
        self.timer = None
        self.control = DaemonControl()
        self.outputIsOn = False
        self.timer_loop = time.time()

        # Initialize custom options
        self.measurement_device_id = None
        self.measurement_measurement_id = None
        self.output_device_id = None
        self.output_measurement_id = None
        self.output_channel_id = None
        self.setpoint = None
        self.hysteresis = None
        self.direction = None
        self.output_channel = None
        self.update_period = None

        # Set custom options
        custom_function = db_retrieve_table_daemon(CustomController,
                                                   unique_id=unique_id)
        self.setup_custom_options(FUNCTION_INFORMATION['custom_options'],
                                  custom_function)

        self.output_channel = self.get_output_channel_from_channel_id(
            self.output_channel_id)

        self.initialize_variables()
コード例 #12
0
    def __init__(self, ready, unique_id, testing=False):
        threading.Thread.__init__(self)
        super(CustomModule, self).__init__(ready,
                                           unique_id=unique_id,
                                           name=__name__)

        self.unique_id = unique_id
        self.log_level_debug = None

        self.control = DaemonControl()

        # Initialize custom options
        self.text_1 = None
        self.integer_1 = None
        self.float_1 = None
        self.bool_1 = None
        self.select_1 = None
        self.select_measurement_1_device_id = None
        self.select_measurement_1_measurement_id = None
        self.output_1_device_id = None
        self.output_1_measurement_id = None
        self.output_1_channel_id = None
        self.select_device_1_id = None
        self.select_device_2_id = None

        # Set custom options
        custom_function = db_retrieve_table_daemon(CustomController,
                                                   unique_id=unique_id)
        self.setup_custom_options(FUNCTION_INFORMATION['custom_options'],
                                  custom_function)

        # Get selected output channel number
        self.output_1_channel = self.get_output_channel_from_channel_id(
            self.output_1_channel_id)

        if not testing:
            pass
コード例 #13
0
ファイル: utils_pid.py プロジェクト: phaseiced/Mycodo
def pid_manipulate(pid_id, action):
    if action not in ['Hold', 'Pause', 'Resume']:
        flash('{}: {}'.format(TRANSLATIONS['invalid']['title'], action),
              "error")
        return 1

    try:
        mod_pid = PID.query.filter(PID.unique_id == pid_id).first()
        if action == 'Hold':
            mod_pid.is_held = True
            mod_pid.is_paused = False
        elif action == 'Pause':
            mod_pid.is_paused = True
            mod_pid.is_held = False
        elif action == 'Resume':
            mod_pid.is_activated = True
            mod_pid.is_held = False
            mod_pid.is_paused = False
        db.session.commit()

        control = DaemonControl()
        return_value = None
        if action == 'Hold':
            return_value = control.pid_hold(pid_id)
        elif action == 'Pause':
            return_value = control.pid_pause(pid_id)
        elif action == 'Resume':
            return_value = control.pid_resume(pid_id)
        if return_value:
            flash(
                '{}: {}: {}: {}'.format(TRANSLATIONS['controller']['title'],
                                        TRANSLATIONS['pid']['title'], action,
                                        return_value), "success")
    except Exception as err:
        flash(
            "{}: {}: {}".format(TRANSLATIONS['Error']['title'],
                                TRANSLATIONS['PID']['title'], err), "error")
コード例 #14
0
ファイル: pid_autotune.py プロジェクト: lulzzz/Mycodo
    def __init__(self, function, testing=False):
        super(CustomModule, self).__init__(function,
                                           testing=testing,
                                           name=__name__)

        self.autotune = None
        self.autotune_active = None
        self.control_variable = None
        self.timestamp = None
        self.timer_loop = None
        self.control = DaemonControl()

        # Initialize custom options
        self.measurement_device_id = None
        self.measurement_measurement_id = None
        self.output_device_id = None
        self.output_measurement_id = None
        self.output_channel_id = None
        self.setpoint = None
        self.period = None
        self.noiseband = None
        self.outstep = None
        self.direction = None

        self.output_channel = None

        # Set custom options
        custom_function = db_retrieve_table_daemon(CustomController,
                                                   unique_id=self.unique_id)
        self.setup_custom_options(FUNCTION_INFORMATION['custom_options'],
                                  custom_function)

        self.output_channel = self.get_output_channel_from_channel_id(
            self.output_channel_id)

        if not testing:
            self.initialize_variables()
コード例 #15
0
ファイル: utils_pid.py プロジェクト: magichammer/Mycodo
def pid_manipulate(pid_id, action):
    if action not in ['Hold', 'Pause', 'Resume']:
        flash(gettext("Invalid PID action: %(act)s", act=action), "error")
        return 1

    try:
        mod_pid = PID.query.filter(PID.unique_id == pid_id).first()
        if action == 'Hold':
            mod_pid.is_held = True
            mod_pid.is_paused = False
        elif action == 'Pause':
            mod_pid.is_paused = True
            mod_pid.is_held = False
        elif action == 'Resume':
            mod_pid.is_activated = True
            mod_pid.is_held = False
            mod_pid.is_paused = False
        db.session.commit()

        control = DaemonControl()
        return_value = None
        if action == 'Hold':
            return_value = control.pid_hold(pid_id)
        elif action == 'Pause':
            return_value = control.pid_pause(pid_id)
        elif action == 'Resume':
            return_value = control.pid_resume(pid_id)
        if return_value:
            flash(
                gettext(
                    "Daemon response to PID controller %(act)s command: "
                    "%(rval)s",
                    act=action,
                    rval=return_value), "success")
    except Exception as err:
        flash(gettext("Error: %(err)s", err='PID: {msg}'.format(msg=err)),
              "error")
コード例 #16
0
def pid_manipulate(pid_id, action):
    messages = {
        "success": [],
        "info": [],
        "warning": [],
        "error": []
    }

    if action not in ['Hold', 'Pause', 'Resume']:
        messages["error"].append(
            '{}: {}'.format(TRANSLATIONS['invalid']['title'], action))
        return messages

    try:
        control = DaemonControl()
        return_value = None
        if action == 'Hold':
            return_value = control.pid_hold(pid_id)
        elif action == 'Pause':
            return_value = control.pid_pause(pid_id)
        elif action == 'Resume':
            return_value = control.pid_resume(pid_id)
        if return_value:
            messages["success"].append(
                '{}: {}: {}: {}'.format(
                    TRANSLATIONS['controller']['title'],
                    TRANSLATIONS['pid']['title'],
                    action,
                    return_value))
    except Exception as err:
        messages["error"].append(
            "{}: {}: {}".format(
                TRANSLATIONS['Error']['title'],
                TRANSLATIONS['PID']['title'], err))

    return messages
コード例 #17
0
ファイル: utils_input.py プロジェクト: weiplanet/Mycodo
def force_acquire_measurements(unique_id):
    action = '{action}, {controller}'.format(
        action=gettext("Force Measurements"),
        controller=TRANSLATIONS['input']['title'])
    error = []

    try:
        mod_input = Input.query.filter(
            Input.unique_id == unique_id).first()

        if not mod_input.is_activated:
            error.append(gettext(
                "Activate controller before attempting to force the acquisition of measurements"))

        if not error:
            control = DaemonControl()
            status = control.input_force_measurements(unique_id)
            if status[0]:
                flash("Force Input Measurement: {}".format(status[1]), "error")
            else:
                flash("Force Input Measurement: {}".format(status[1]), "success")
    except Exception as except_msg:
        error.append(except_msg)
    flash_success_errors(error, action, url_for('routes_page.page_data'))
コード例 #18
0
ファイル: routes_general.py プロジェクト: donpesce/Mycodo
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.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.id)
        return return_str
    elif state == 'pause_pid':
        pid.is_paused = True
        pid.save()
        return_str = daemon.pid_pause(pid.id)
        return return_str
    elif state == 'hold_pid':
        pid.is_held = True
        pid.save()
        return_str = daemon.pid_hold(pid.id)
        return return_str
    elif state == 'resume_pid':
        pid.is_held = False
        pid.is_paused = False
        pid.save()
        return_str = daemon.pid_resume(pid.id)
        return return_str
コード例 #19
0
ファイル: utils_output.py プロジェクト: kizniche/Mycodo
def manipulate_output(action, output_id):
    """
    Add, delete, and modify output settings while the daemon is active

    :param output_id: output ID in the SQL database
    :type output_id: str
    :param action: "Add", "Delete", or "Modify"
    :type action: str
    """
    messages = {
        "success": [],
        "info": [],
        "warning": [],
        "error": []
    }

    try:
        control = DaemonControl()
        return_values = control.output_setup(action, output_id)
        if return_values and len(return_values) > 1:
            if return_values[0]:
                messages["error"].append(gettext("%(err)s",
                    err='{action} Output: Daemon response: {msg}'.format(
                        action=action,
                        msg=return_values[1])))
            else:
                messages["success"].append(gettext("%(err)s",
                    err='{action} Output: Daemon response: {msg}'.format(
                        action=gettext(action),
                        msg=return_values[1])))
    except Exception as msg:
        messages["error"].append(gettext("%(err)s",
            err='{action} Output: Could not connect to Daemon: {error}'.format(
                action=action, error=msg)))

    return messages
コード例 #20
0
    def __init__(self, ready, unique_id):
        threading.Thread.__init__(self)
        super(ConditionalController, self).__init__(ready,
                                                    unique_id=unique_id,
                                                    name=__name__)

        self.unique_id = unique_id
        self.sample_rate = None

        self.control = DaemonControl()

        self.pause_loop = False
        self.verify_pause_loop = True
        self.is_activated = None
        self.smtp_max_count = None
        self.email_count = None
        self.allowed_to_send_notice = None
        self.smtp_wait_timer = None
        self.timer_period = None
        self.period = None
        self.start_offset = None
        self.refractory_period = None
        self.log_level_debug = None
        self.conditional_statement = None
        self.timer_refractory_period = None
        self.smtp_wait_timer = None
        self.timer_period = None
        self.timer_start_time = None
        self.timer_end_time = None
        self.unique_id_1 = None
        self.unique_id_2 = None
        self.trigger_actions_at_period = None
        self.trigger_actions_at_start = None
        self.method_start_time = None
        self.method_end_time = None
        self.method_start_act = None
コード例 #21
0
def conditional_mod(form):
    """Modify a Conditional."""
    messages = {
        "success": [],
        "info": [],
        "warning": [],
        "error": [],
        "page_refresh": True,
        "return_text": [],
        "name": None
    }

    try:
        if current_app.config['TESTING']:
            cmd_status = None
            pylint_message = ""
        else:
            messages[
                "error"], lines_code, cmd_status, cmd_out = save_conditional_code(
                    messages["error"],
                    form.conditional_statement.data,
                    form.conditional_status.data,
                    form.function_id.data,
                    ConditionalConditions.query.all(),
                    Actions.query.all(),
                    timeout=form.pyro_timeout.data,
                    test=True)

            pylint_message = Markup(
                '<pre>\n\n'
                'Full Conditional Statement code:\n\n{code}\n\n'
                'Conditional Statement code analysis:\n\n{report}'
                '</pre>'.format(code=lines_code,
                                report=cmd_out.decode("utf-8")))

        cond_mod = Conditional.query.filter(
            Conditional.unique_id == form.function_id.data).first()
        cond_mod.name = form.name.data
        messages["name"] = form.name.data
        cond_mod.conditional_statement = form.conditional_statement.data
        cond_mod.conditional_status = form.conditional_status.data
        cond_mod.period = form.period.data
        cond_mod.log_level_debug = form.log_level_debug.data
        cond_mod.message_include_code = form.message_include_code.data
        cond_mod.start_offset = form.start_offset.data
        cond_mod.pyro_timeout = form.pyro_timeout.data

        if cmd_status:
            messages["warning"].append(
                "pylint returned with status: {}".format(cmd_status))

        if pylint_message:
            messages["info"].append(
                "Review your code for issues and test before putting it "
                "into a production environment.")
            messages["return_text"].append(pylint_message)

        if not messages["error"]:
            db.session.commit()
            messages["success"].append('{action} {controller}'.format(
                action=TRANSLATIONS['modify']['title'],
                controller=TRANSLATIONS['conditional']['title']))

            if cond_mod.is_activated:
                control = DaemonControl()
                return_value = control.refresh_daemon_conditional_settings(
                    form.function_id.data)
                messages["success"].append(
                    gettext("Daemon response: %(resp)s", resp=return_value))

    except sqlalchemy.exc.OperationalError as except_msg:
        messages["error"].append(str(except_msg))
    except sqlalchemy.exc.IntegrityError as except_msg:
        messages["error"].append(str(except_msg))
    except Exception as except_msg:
        messages["error"].append(str(except_msg))

    return messages
コード例 #22
0
def pid_mod(form_mod_pid_base,
            form_mod_pid_pwm_raise, form_mod_pid_pwm_lower,
            form_mod_pid_relay_raise, form_mod_pid_relay_lower):
    action = u'{action} {controller}'.format(
        action=gettext(u"Modify"),
        controller=gettext(u"PID"))
    error = []

    if not form_mod_pid_base.validate():
        flash_form_errors(form_mod_pid_base)

    sensor_unique_id = form_mod_pid_base.measurement.data.split(',')[0]
    sensor = Input.query.filter(
        Input.unique_id == sensor_unique_id).first()
    if not sensor:
        error.append(gettext(u"A valid sensor is required"))

    mod_pid = PID.query.filter(
        PID.id == form_mod_pid_base.pid_id.data).first()

    # Check if a specific setting can be modified if the PID is active
    if mod_pid.is_activated:
        error = can_set_relay(error,
                              form_mod_pid_base.pid_id.data,
                              form_mod_pid_base.raise_relay_id.data,
                              form_mod_pid_base.lower_relay_id.data)

    mod_pid.name = form_mod_pid_base.name.data
    mod_pid.measurement = form_mod_pid_base.measurement.data
    mod_pid.direction = form_mod_pid_base.direction.data
    mod_pid.period = form_mod_pid_base.period.data
    mod_pid.max_measure_age = form_mod_pid_base.max_measure_age.data
    mod_pid.setpoint = form_mod_pid_base.setpoint.data
    mod_pid.p = form_mod_pid_base.k_p.data
    mod_pid.i = form_mod_pid_base.k_i.data
    mod_pid.d = form_mod_pid_base.k_d.data
    mod_pid.integrator_min = form_mod_pid_base.integrator_max.data
    mod_pid.integrator_max = form_mod_pid_base.integrator_min.data
    if form_mod_pid_base.method_id.data:
        mod_pid.method_id = form_mod_pid_base.method_id.data
    else:
        mod_pid.method_id = None

    if form_mod_pid_base.raise_relay_id.data:
        raise_relay_type = Output.query.filter(
            Output.id == int(form_mod_pid_base.raise_relay_id.data)).first().relay_type
        if mod_pid.raise_relay_id == int(form_mod_pid_base.raise_relay_id.data):
            if raise_relay_type == 'pwm':
                if not form_mod_pid_pwm_raise.validate():
                    flash_form_errors(form_mod_pid_pwm_raise)
                else:
                    mod_pid.raise_min_duration = form_mod_pid_pwm_raise.raise_min_duty_cycle.data
                    mod_pid.raise_max_duration = form_mod_pid_pwm_raise.raise_max_duty_cycle.data
            else:
                if not form_mod_pid_relay_raise.validate():
                    flash_form_errors(form_mod_pid_relay_raise)
                else:
                    mod_pid.raise_min_duration = form_mod_pid_relay_raise.raise_min_duration.data
                    mod_pid.raise_max_duration = form_mod_pid_relay_raise.raise_max_duration.data
                    mod_pid.raise_min_off_duration = form_mod_pid_relay_raise.raise_min_off_duration.data
        else:
            if raise_relay_type == 'pwm':
                mod_pid.raise_min_duration = 2
                mod_pid.raise_max_duration = 98
            else:
                mod_pid.raise_min_duration = 0
                mod_pid.raise_max_duration = 0
                mod_pid.raise_min_off_duration = 0
        mod_pid.raise_relay_id = form_mod_pid_base.raise_relay_id.data
    else:
        mod_pid.raise_relay_id = None

    if form_mod_pid_base.lower_relay_id.data:
        lower_relay_type = Output.query.filter(
            Output.id == int(form_mod_pid_base.lower_relay_id.data)).first().relay_type
        if mod_pid.lower_relay_id == int(form_mod_pid_base.lower_relay_id.data):
            if lower_relay_type == 'pwm':
                if not form_mod_pid_pwm_lower.validate():
                    flash_form_errors(form_mod_pid_pwm_lower)
                else:
                    mod_pid.lower_min_duration = form_mod_pid_pwm_lower.lower_min_duty_cycle.data
                    mod_pid.lower_max_duration = form_mod_pid_pwm_lower.lower_max_duty_cycle.data
            else:
                if not form_mod_pid_relay_lower.validate():
                    flash_form_errors(form_mod_pid_relay_lower)
                else:
                    mod_pid.lower_min_duration = form_mod_pid_relay_lower.lower_min_duration.data
                    mod_pid.lower_max_duration = form_mod_pid_relay_lower.lower_max_duration.data
                    mod_pid.lower_min_off_duration = form_mod_pid_relay_lower.lower_min_off_duration.data
        else:
            if lower_relay_type == 'pwm':
                mod_pid.lower_min_duration = 2
                mod_pid.lower_max_duration = 98
            else:
                mod_pid.lower_min_duration = 0
                mod_pid.lower_max_duration = 0
                mod_pid.lower_min_off_duration = 0
        mod_pid.lower_relay_id = form_mod_pid_base.lower_relay_id.data
    else:
        mod_pid.lower_relay_id = None

    if (mod_pid.raise_relay_id and mod_pid.lower_relay_id and
                mod_pid.raise_relay_id == mod_pid.lower_relay_id):
        error.append(gettext(u"Raise and lower outputs cannot be the same"))

    try:
        if not error:
            db.session.commit()
            # If the controller is active or paused, refresh variables in thread
            if mod_pid.is_activated:
                control = DaemonControl()
                return_value = control.pid_mod(form_mod_pid_base.pid_id.data)
                flash(gettext(
                    u"PID Controller settings refresh response: %(resp)s",
                    resp=return_value), "success")
    except Exception as except_msg:
        error.append(except_msg)
    flash_success_errors(error, action, url_for('page_routes.page_pid'))
コード例 #23
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_on(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())
コード例 #24
0
def controller_activate_deactivate(controller_action, controller_type,
                                   controller_id):
    """
    Activate or deactivate controller

    :param controller_action: Activate or deactivate
    :type controller_action: str
    :param controller_type: The controller type (LCD, Math, PID, Input, Timer)
    :type controller_type: str
    :param controller_id: Controller with ID to activate or deactivate
    :type controller_id: str
    """
    if not user_has_permission('edit_controllers'):
        return redirect(url_for('routes_general.home'))

    activated = bool(controller_action == 'activate')

    translated_names = {
        "Conditional": gettext("Conditional"),
        "Input": gettext("Input"),
        "LCD": gettext("LCD"),
        "Math": gettext("Math"),
        "PID": gettext("PID"),
        "Timer": gettext("Timer")
    }

    mod_controller = None
    if controller_type == 'Conditional':
        mod_controller = Conditional.query.filter(
            Conditional.id == int(controller_id)).first()
    elif controller_type == 'Input':
        mod_controller = Input.query.filter(
            Input.id == int(controller_id)).first()
    elif controller_type == 'LCD':
        mod_controller = LCD.query.filter(LCD.id == int(controller_id)).first()
    elif controller_type == 'Math':
        mod_controller = Math.query.filter(
            Math.id == int(controller_id)).first()
    elif controller_type == 'PID':
        mod_controller = PID.query.filter(PID.id == int(controller_id)).first()
    elif controller_type == 'Timer':
        mod_controller = Timer.query.filter(
            Timer.id == int(controller_id)).first()

    if mod_controller is None:
        flash(
            "{type} Controller {id} doesn't exist".format(type=controller_type,
                                                          id=controller_id),
            "error")
        return redirect(url_for('routes_general.home'))

    try:
        mod_controller.is_activated = activated
        db.session.commit()

        if activated:
            flash(
                gettext("%(cont)s controller activated in SQL database",
                        cont=translated_names[controller_type]), "success")
        else:
            flash(
                gettext("%(cont)s controller deactivated in SQL database",
                        cont=translated_names[controller_type]), "success")
    except Exception as except_msg:
        flash(
            gettext("Error: %(err)s", err='SQL: {msg}'.format(msg=except_msg)),
            "error")

    try:
        control = DaemonControl()
        if controller_action == 'activate':
            return_values = control.controller_activate(
                controller_type, int(controller_id))
        else:
            return_values = control.controller_deactivate(
                controller_type, int(controller_id))
        if return_values[0]:
            flash("{err}".format(err=return_values[1]), "error")
        else:
            flash("{err}".format(err=return_values[1]), "success")
    except Exception as except_msg:
        flash(
            gettext("Error: %(err)s",
                    err='Daemon: {msg}'.format(msg=except_msg)), "error")
コード例 #25
0
    def initialize_input(self):
        from mycodo.mycodo_client import DaemonControl

        self.control = DaemonControl()
        self.sensor = AM2315(self.input_dev.i2c_bus)
コード例 #26
0
ファイル: controller_pid.py プロジェクト: ldm-top/Mycodo
    def __init__(self, ready, pid_id):
        threading.Thread.__init__(self)

        self.logger = logging.getLogger("mycodo.pid_{id}".format(id=pid_id))

        self.running = False
        self.thread_startup_timer = timeit.default_timer()
        self.thread_shutdown_timer = 0
        self.ready = ready
        self.pid_id = pid_id
        self.pid_unique_id = db_retrieve_table_daemon(
            PID, device_id=self.pid_id).unique_id
        self.control = DaemonControl()

        self.control_variable = 0.0
        self.derivator = 0.0
        self.integrator = 0.0
        self.error = 0.0
        self.P_value = None
        self.I_value = None
        self.D_value = None
        self.lower_seconds_on = 0.0
        self.raise_seconds_on = 0.0
        self.lower_duty_cycle = 0.0
        self.raise_duty_cycle = 0.0
        self.last_time = None
        self.last_measurement = None
        self.last_measurement_success = False

        self.is_activated = None
        self.is_held = None
        self.is_paused = None
        self.measurement = None
        self.method_id = None
        self.direction = None
        self.raise_output_id = None
        self.raise_min_duration = None
        self.raise_max_duration = None
        self.raise_min_off_duration = None
        self.lower_output_id = None
        self.lower_min_duration = None
        self.lower_max_duration = None
        self.lower_min_off_duration = None
        self.Kp = None
        self.Ki = None
        self.Kd = None
        self.integrator_min = None
        self.integrator_max = None
        self.period = None
        self.max_measure_age = None
        self.default_setpoint = None
        self.setpoint = None
        self.store_lower_as_negative = None

        # Hysteresis options
        self.band = None
        self.allow_raising = False
        self.allow_lowering = False

        self.dev_unique_id = None
        self.input_duration = None

        self.raise_output_type = None
        self.lower_output_type = None

        self.first_start = True

        self.initialize_values()

        self.timer = t.time() + self.period

        # Check if a method is set for this PID
        self.method_start_act = None
        if self.method_id:
            self.setup_method(self.method_id)
コード例 #27
0
ファイル: widget_pid.py プロジェクト: rosaLux161/Mycodo
def last_data_pid(pid_id, input_period):
    """Return the most recent time and value from influxdb."""
    if not current_user.is_authenticated:
        return "You are not logged in and cannot access this endpoint"
    if not str_is_float(input_period):
        return '', 204

    try:
        pid = PID.query.filter(PID.unique_id == pid_id).first()

        if len(pid.measurement.split(',')) == 2:
            device_id = pid.measurement.split(',')[0]
            measurement_id = pid.measurement.split(',')[1]
        else:
            device_id = None
            measurement_id = None

        actual_measurement = DeviceMeasurements.query.filter(
            DeviceMeasurements.unique_id == measurement_id).first()
        if actual_measurement:
            actual_conversion = Conversion.query.filter(
                Conversion.unique_id ==
                actual_measurement.conversion_id).first()
        else:
            actual_conversion = None

        (actual_channel, actual_unit,
         actual_measurement) = return_measurement_info(actual_measurement,
                                                       actual_conversion)

        setpoint_unit = None
        if pid and ',' in pid.measurement:
            pid_measurement = pid.measurement.split(',')[1]
            setpoint_measurement = DeviceMeasurements.query.filter(
                DeviceMeasurements.unique_id == pid_measurement).first()
            if setpoint_measurement:
                conversion = Conversion.query.filter(
                    Conversion.unique_id ==
                    setpoint_measurement.conversion_id).first()
                _, setpoint_unit, _ = return_measurement_info(
                    setpoint_measurement, conversion)

        p_value = return_point_timestamp(pid_id,
                                         'pid_value',
                                         input_period,
                                         measurement='pid_p_value')
        i_value = return_point_timestamp(pid_id,
                                         'pid_value',
                                         input_period,
                                         measurement='pid_i_value')
        d_value = return_point_timestamp(pid_id,
                                         'pid_value',
                                         input_period,
                                         measurement='pid_d_value')
        if None not in (p_value[1], i_value[1], d_value[1]):
            pid_value = [
                p_value[0],
                f'{float(p_value[1]) + float(i_value[1]) + float(d_value[1]):.3f}'
            ]
        else:
            pid_value = None

        setpoint_band = None
        if pid.band:
            try:
                daemon = DaemonControl()
                setpoint_band = daemon.pid_get(pid.unique_id, 'setpoint_band')
            except:
                logger.debug("Couldn't get setpoint")

        live_data = {
            'activated':
            pid.is_activated,
            'paused':
            pid.is_paused,
            'held':
            pid.is_held,
            'setpoint':
            return_point_timestamp(pid_id,
                                   setpoint_unit,
                                   input_period,
                                   channel=0),
            'setpoint_band':
            setpoint_band,
            'pid_p_value':
            p_value,
            'pid_i_value':
            i_value,
            'pid_d_value':
            d_value,
            'pid_pid_value':
            pid_value,
            'duration_time':
            return_point_timestamp(pid_id,
                                   's',
                                   input_period,
                                   measurement='duration_time'),
            'duty_cycle':
            return_point_timestamp(pid_id,
                                   'percent',
                                   input_period,
                                   measurement='duty_cycle'),
            'actual':
            return_point_timestamp(device_id,
                                   actual_unit,
                                   input_period,
                                   measurement=actual_measurement,
                                   channel=actual_channel)
        }
        return jsonify(live_data)
    except KeyError:
        logger.debug("No Data returned form influxdb")
        return '', 204
    except Exception as err:
        logger.exception(f"URL for 'last_pid' raised and error: {err}")
        return '', 204
コード例 #28
0
def conditional_mod(form):
    """Modify a Conditional"""
    error = []
    action = '{action} {controller}'.format(
        action=TRANSLATIONS['modify']['title'],
        controller=TRANSLATIONS['conditional']['title'])

    try:
        pre_statement = """import os, random, sys
sys.path.append(os.path.abspath('/var/mycodo-root'))
from mycodo.mycodo_client import DaemonControl

control = DaemonControl()
message = ''

# The following functions are used to test the Conditional code.
# The functions that are used in the production environment will
# return the proper values and affect the proper systems when called.

def measure(condition_id):
    # pylint: disable=unused-argument
    return random.choice([
        None, -100000, -10000, -1000, -100, -10,
        0, 1, 10, 100, 1000, 10000, 100000
    ])

def measure_dict(condition_id):
    # pylint: disable=unused-argument
    return [
        {'time': '2019-04-24T18:01:00.000Z', 'value': -100000},
        {'time': '2019-04-24T18:02:00.000Z', 'value': -10000},
        {'time': '2019-04-24T18:03:00.000Z', 'value': -1000},
        {'time': '2019-04-24T18:04:00.000Z', 'value': -100},
        {'time': '2019-04-24T18:05:00.000Z', 'value': -10},
        {'time': '2019-04-24T18:06:00.000Z', 'value': -1},
        {'time': '2019-04-24T18:07:00.000Z', 'value': 1},
        {'time': '2019-04-24T18:08:00.000Z', 'value': 10},
        {'time': '2019-04-24T18:09:00.000Z', 'value': 100},
        {'time': '2019-04-24T18:10:00.000Z', 'value': 1000},
        {'time': '2019-04-24T18:11:00.000Z', 'value': 10000},
        {'time': '2019-04-24T18:12:00.000Z', 'value': 100000},
    ]

def run_all_actions(message=message):
    # pylint: disable=unused-argument
    pass

def run_action(action_id, message=message):
    # pylint: disable=unused-argument
    pass

###########################
##### BEGIN USER CODE #####
###########################

"""

        cond_statement = (pre_statement + form.conditional_statement.data)

        if len(cond_statement.splitlines()) > 999:
            error.append(
                "Too many lines in code. Reduce code to less than 1000 lines.")

        lines_code = ''
        for line_num, each_line in enumerate(cond_statement.splitlines(), 1):
            if len(str(line_num)) == 3:
                line_spacing = ''
            elif len(str(line_num)) == 2:
                line_spacing = ' '
            else:
                line_spacing = '  '
            lines_code += '{sp}{ln}: {line}\n'.format(sp=line_spacing,
                                                      ln=line_num,
                                                      line=each_line)

        path_file = '/tmp/conditional_code_{}.py'.format(
            str(uuid.uuid4()).split('-')[0])
        with open(path_file, 'w') as out:
            out.write('{}\n'.format(cond_statement))

        cmd_test = 'export PYTHONPATH=$PYTHONPATH:/var/mycodo-root && ' \
                   'pylint3 -d I,W0621,C0103,C0111,C0301,C0327,C0410,C0413 {path}'.format(
            path=path_file)
        cmd_out, cmd_err, cmd_status = cmd_output(cmd_test)

        os.remove(path_file)

        message = Markup('<pre>\n\n'
                         'Full Conditional Statement code:\n\n{code}\n\n'
                         'Conditional Statement code analysis:\n\n{report}'
                         '</pre>'.format(code=lines_code,
                                         report=cmd_out.decode("utf-8")))
        if cmd_status:
            flash(
                'Error(s) were found while evaluating your code. Review '
                'the error(s), below, and fix them before activating your '
                'Conditional.', 'error')
            flash(message, 'error')
        else:
            flash(
                "No errors were found while evaluating your code. However, "
                "this doesn't mean your code will perform as expected. "
                "Review your code for issues and test your Conditional "
                "before putting it into a production environment.", 'success')
            flash(message, 'success')

        cond_mod = Conditional.query.filter(
            Conditional.unique_id == form.function_id.data).first()
        cond_mod.name = form.name.data
        cond_mod.conditional_statement = form.conditional_statement.data
        cond_mod.period = form.period.data
        cond_mod.log_level_debug = form.log_level_debug.data
        cond_mod.start_offset = form.start_offset.data
        cond_mod.refractory_period = form.refractory_period.data

        if not error:
            db.session.commit()

            if cond_mod.is_activated:
                control = DaemonControl()
                return_value = control.refresh_daemon_conditional_settings(
                    form.function_id.data)
                flash(gettext("Daemon response: %(resp)s", resp=return_value),
                      "success")

    except sqlalchemy.exc.OperationalError as except_msg:
        error.append(except_msg)
    except sqlalchemy.exc.IntegrityError as except_msg:
        error.append(except_msg)
    except Exception as except_msg:
        error.append(except_msg)

    flash_success_errors(error, action, url_for('routes_page.page_function'))
コード例 #29
0
ファイル: utils_general.py プロジェクト: M-Mushman/Mycodo
def controller_activate_deactivate(controller_action,
                                   controller_type,
                                   controller_id):
    """
    Activate or deactivate controller

    :param controller_action: Activate or deactivate
    :type controller_action: str
    :param controller_type: The controller type (Conditional, LCD, Math, PID, Input)
    :type controller_type: str
    :param controller_id: Controller with ID to activate or deactivate
    :type controller_id: str
    """
    if not user_has_permission('edit_controllers'):
        return redirect(url_for('routes_general.home'))

    error = []

    activated = bool(controller_action == 'activate')

    translated_names = {
        "Conditional": TRANSLATIONS['conditional']['title'],
        "Input": TRANSLATIONS['input']['title'],
        "LCD": TRANSLATIONS['lcd']['title'],
        "Math": TRANSLATIONS['math']['title'],
        "PID": TRANSLATIONS['pid']['title'],
        "Trigger": TRANSLATIONS['trigger']['title']
    }

    mod_controller = None
    if controller_type == 'Conditional':
        mod_controller = Conditional.query.filter(
            Conditional.unique_id == controller_id).first()
    elif controller_type == 'Input':
        mod_controller = Input.query.filter(
            Input.unique_id == controller_id).first()
        if activated:
            error = check_for_valid_unit_and_conversion(controller_id, error)
    elif controller_type == 'LCD':
        mod_controller = LCD.query.filter(
            LCD.unique_id == controller_id).first()
    elif controller_type == 'Math':
        mod_controller = Math.query.filter(
            Math.unique_id == controller_id).first()
        if activated:
            error = check_for_valid_unit_and_conversion(controller_id, error)
    elif controller_type == 'PID':
        mod_controller = PID.query.filter(
            PID.unique_id == controller_id).first()
        if activated:
            error = check_for_valid_unit_and_conversion(controller_id, error)
    elif controller_type == 'Trigger':
        mod_controller = Trigger.query.filter(
            Trigger.unique_id == controller_id).first()

    if mod_controller is None:
        flash("{type} Controller {id} doesn't exist".format(
            type=controller_type, id=controller_id), "error")
        return redirect(url_for('routes_general.home'))

    try:
        if not error:
            mod_controller.is_activated = activated
            db.session.commit()

            if activated:
                flash(
                    "{} {} (SQL)".format(
                        translated_names[controller_type],
                        TRANSLATIONS['activate']['title']),
                    "success")
            else:
                flash(
                    "{} {} (SQL)".format(
                        translated_names[controller_type],
                        TRANSLATIONS['deactivate']['title']),
                    "success")
    except Exception as except_msg:
        flash(gettext("Error: %(err)s",
                      err='SQL: {msg}'.format(msg=except_msg)),
              "error")

    try:
        if not error:
            control = DaemonControl()
            if controller_action == 'activate':
                return_values = control.controller_activate(
                    controller_type,controller_id)
            else:
                return_values = control.controller_deactivate(
                    controller_type, controller_id)
            if return_values[0]:
                flash("{err}".format(err=return_values[1]), "error")
            else:
                flash("{err}".format(err=return_values[1]), "success")
    except Exception as except_msg:
        flash('{}: {}'.format(TRANSLATIONS['error']['title'], except_msg),
              "error")

    for each_error in error:
        flash(each_error, 'error')
コード例 #30
0
def widget_add(form_base, request_form):
    """Add a widget to the dashboard"""
    action = '{action} {controller}'.format(
        action=TRANSLATIONS['add']['title'],
        controller=TRANSLATIONS['widget']['title'])
    error = []

    dict_widgets = parse_widget_information()

    if form_base.widget_type.data:
        widget_name = form_base.widget_type.data
    else:
        widget_name = ''
        error.append("Missing widget name")

    if current_app.config['TESTING']:
        dep_unmet = False
    else:
        dep_unmet, _ = return_dependencies(widget_name)
        if dep_unmet:
            list_unmet_deps = []
            for each_dep in dep_unmet:
                list_unmet_deps.append(each_dep[0])
            error.append("The {dev} device you're trying to add has unmet dependencies: {dep}".format(
                dev=widget_name, dep=', '.join(list_unmet_deps)))

    new_widget = Widget()
    new_widget.dashboard_id = form_base.dashboard_id.data
    new_widget.graph_type = widget_name
    new_widget.name = form_base.name.data
    new_widget.font_em_name = form_base.font_em_name.data
    new_widget.enable_drag_handle = form_base.enable_drag_handle.data
    new_widget.refresh_duration = form_base.refresh_duration.data

    # Find where the next widget should be placed on the grid
    # Finds the lowest position to create as the new Widget's starting position
    position_y_start = 0
    for each_widget in Widget.query.filter(
            Widget.dashboard_id == form_base.dashboard_id.data).all():
        highest_position = each_widget.position_y + each_widget.height
        if highest_position > position_y_start:
            position_y_start = highest_position
    new_widget.position_y = position_y_start

    # widget add options
    if widget_name in dict_widgets:
        def dict_has_value(key):
            if (key in dict_widgets[widget_name] and
                    (dict_widgets[widget_name][key] or dict_widgets[widget_name][key] == 0)):
                return True

        if dict_has_value('widget_width'):
            new_widget.width = dict_widgets[widget_name]['widget_width']
        if dict_has_value('widget_height'):
            new_widget.height = dict_widgets[widget_name]['widget_height']

    # Generate string to save from custom options
    error, custom_options = custom_options_return_json(
        error, dict_widgets, request_form, device=widget_name, use_defaults=True)
    new_widget.custom_options = custom_options

    #
    # Execute at Creation
    #

    if ('execute_at_creation' in dict_widgets[widget_name] and
            not current_app.config['TESTING']):
        dict_widgets[widget_name]['execute_at_creation'](
            new_widget, dict_widgets[widget_name])

    try:
        if not error:
            new_widget.save()

            # Refresh widget settings
            control = DaemonControl()
            control.widget_add_refresh(new_widget.unique_id)

            flash(gettext(
                "{dev} with ID %(id)s successfully added".format(
                    dev=dict_widgets[form_base.widget_type.data]['widget_name']),
                id=new_widget.id),
                "success")
    except sqlalchemy.exc.OperationalError as except_msg:
        error.append(except_msg)
    except sqlalchemy.exc.IntegrityError as except_msg:
        error.append(except_msg)

    return dep_unmet