Esempio n. 1
0
 def exposed_system_control(self, cmd):
     """
     Execute a command as root. A list of commands are provded to prevent
     execution of arbitrary code.
     """
     if cmd == 'restart':
         return cmd_output('shutdown now -r')
     elif cmd == 'shutdown':
         return cmd_output('shutdown now -h')
     return 1
Esempio n. 2
0
 def exposed_system_control(self, cmd):
     """
     Execute a command as root. A list of commands are provded to prevent
     execution of arbitrary code.
     """
     if cmd == 'restart':
         return cmd_output('shutdown now -r')
     elif cmd == 'shutdown':
         return cmd_output('shutdown now -h')
     return 1
    def checkConditionals(self, cond_id):
        """
        Check if any sensor conditional statements are activated and
        execute their actions if the conditional is true.

        For example, if measured temperature is above 30C, notify [email protected]

        :rtype: None

        :param each_cond: Object of SQL table entries for a specific column
        :type each_cond: sqlalchemy object
        """
        attachment_file = False
        attachment_type = False

        last_measurement = self.getLastMeasurement(
            self.cond_measurement_type[cond_id])
        if (last_measurement
                and ((self.cond_direction[cond_id] == 'above'
                      and last_measurement > self.cond_setpoint[cond_id]) or
                     (self.cond_direction[cond_id] == 'below'
                      and last_measurement < self.cond_setpoint[cond_id]))):

            now = time.time()
            timestamp = datetime.datetime.fromtimestamp(now).strftime(
                '%Y-%m-%d %H-%M-%S')
            message = "{}\n[Sensor Conditional {}] {}\n{} {} ".format(
                timestamp, cond_id, self.cond_name[cond_id],
                self.cond_measurement_type[cond_id], last_measurement)
            if self.cond_direction[cond_id] == 'above':
                message += ">"
            elif self.cond_direction[cond_id] == 'below':
                message += "<"
            message += " {} setpoint.".format(self.cond_setpoint[cond_id])

            if (self.cond_relay_id[cond_id]
                    and self.cond_relay_state[cond_id] in ['on', 'off']):
                message += "\nTurning relay {} {}".format(
                    self.cond_relay_id[cond_id],
                    self.cond_relay_state[cond_id])
                if (self.cond_relay_state[cond_id] == 'on'
                        and self.cond_relay_on_duration[cond_id]):
                    message += " for {} seconds".format(
                        self.cond_relay_on_duration[cond_id])
                message += ". "
                relay_on_off = threading.Thread(
                    target=self.control.relay_on_off,
                    args=(
                        self.cond_relay_id[cond_id],
                        self.cond_relay_state[cond_id],
                        self.cond_relay_on_duration[cond_id],
                    ))
                relay_on_off.start()

            # Execute command in shell
            if self.cond_execute_command[cond_id]:
                message += "\nExecute '{}'. ".format(
                    self.cond_execute_command[cond_id])
                cmd_out, cmd_err, cmd_status = cmd_output(
                    self.cond_execute_command[cond_id])
                message += "Status: {}. ".format(cmd_status)

            if self.cond_camera_record[cond_id] in ['photo', 'photoemail']:
                attachment_file = camera_record(INSTALL_DIRECTORY, 'photo')
            elif self.cond_camera_record[cond_id] in ['video', 'videoemail']:
                attachment_file = camera_record(INSTALL_DIRECTORY,
                                                'video',
                                                duration_sec=5)

            if self.cond_email_notify[cond_id]:
                if (self.email_count >= self.smtp_max_count
                        and time.time() < self.smtp_wait_timer[cond_id]):
                    self.allowed_to_send_notice = False
                else:
                    if time.time() > self.smtp_wait_timer[cond_id]:
                        self.email_count = 0
                        self.smtp_wait_timer[cond_id] = time.time() + 3600
                    self.allowed_to_send_notice = True
                self.email_count += 1

                # If the emails per hour limit has not been exceeded
                if self.allowed_to_send_notice:
                    message += "\nNotify {}.".format(
                        self.cond_email_notify[cond_id])
                    # attachment_type != False indicates to
                    # attach a photo or video
                    if self.cond_camera_record[cond_id] == 'photoemail':
                        message += "\nPhoto attached."
                        attachment_type = 'still'
                    elif self.cond_camera_record[cond_id] == 'videoemail':
                        message += "\nVideo attached."
                        attachment_type = 'video'
                    with session_scope(MYCODO_DB_PATH) as new_session:
                        smtp = new_session.query(SMTP).first()
                        send_email(self.logger, smtp.host, smtp.ssl, smtp.port,
                                   smtp.user, smtp.passw, smtp.email_from,
                                   self.cond_email_notify[cond_id], message,
                                   attachment_file, attachment_type)
                else:
                    self.logger.debug(
                        "[Sensor Conditional {}] "
                        "{:.0f} seconds left to be "
                        "allowed to email again.".format(
                            cond_id,
                            (self.smtp_wait_timer[cond_id] - time.time())))

            if self.cond_flash_lcd[cond_id]:
                start_flashing = threading.Thread(
                    target=self.control.flash_lcd,
                    args=(
                        self.cond_flash_lcd[cond_id],
                        1,
                    ))
                start_flashing.start()

            self.logger.debug(message)
        else:
            self.logger.debug("[Sensor Conditional {}] Last measurement "
                              "not found".format(cond_id))
Esempio n. 4
0
    def check_conditionals(self, output_id, state=None, on_duration=None, duty_cycle=None):
        conditionals = db_retrieve_table_daemon(Conditional)
        conditionals = conditionals.filter(
            Conditional.if_relay_id == output_id)
        conditionals = conditionals.filter(
            Conditional.is_activated == True)

        if self.is_on(output_id):
            conditionals = conditionals.filter(
                or_(Conditional.if_relay_state == 'on',
                    Conditional.if_relay_state == 'on_any'))

            on_with_duration = and_(
                Conditional.if_relay_state == 'on',
                Conditional.if_relay_duration == on_duration)
            conditionals = conditionals.filter(
                or_(Conditional.if_relay_state == 'on_any',
                    on_with_duration))

        else:
            conditionals = conditionals.filter(
                Conditional.if_relay_state == 'off')

        for each_conditional in conditionals.all():
            conditional_actions = db_retrieve_table_daemon(ConditionalActions)
            conditional_actions = conditional_actions.filter(
                ConditionalActions.conditional_id == each_conditional.id).all()

            for each_cond_action in conditional_actions:
                now = time.time()
                timestamp = datetime.datetime.fromtimestamp(now).strftime('%Y-%m-%d %H-%M-%S')
                message = u"{ts}\n[Output Conditional {id}] {name}\n".format(
                    ts=timestamp,
                    id=each_cond_action.id,
                    name=each_conditional.name)

                if each_cond_action.do_action == 'relay':
                    if each_cond_action.do_relay_id not in self.output_name:
                        message += u"Error: Invalid output ID {id}.".format(
                            id=each_cond_action.do_relay_id)
                    else:
                        message += u"If output {id} ({name}) turns {state}, Then ".format(
                            id=each_conditional.if_relay_id,
                            name=self.output_name[each_conditional.if_relay_id],
                            state=each_conditional.if_relay_state)
                        message += u"turn output {id} ({name}) {state}".format(
                            id=each_cond_action.do_relay_id,
                            name=self.output_name[each_cond_action.do_relay_id],
                            state=each_cond_action.do_relay_state)

                        if each_cond_action.do_relay_duration == 0:
                            self.output_on_off(each_cond_action.do_relay_id,
                                               each_cond_action.do_relay_state)
                        else:
                            message += u" for {dur} seconds".format(
                                dur=each_cond_action.do_relay_duration)
                            self.output_on_off(each_cond_action.do_relay_id,
                                               each_cond_action.do_relay_state,
                                               duration=each_cond_action.do_relay_duration)
                    message += ".\n"

                elif each_cond_action.do_action == 'command':
                    # Execute command as user mycodo
                    message += u"Execute: '{}'. ".format(
                        each_cond_action.do_action_string)

                    # Check command for variables to replace with values
                    command_str = each_cond_action.do_action_string
                    command_str = command_str.replace(
                        "((output_pin))", str(self.output_pin[output_id]))
                    command_str = command_str.replace(
                        "((output_action))", str(state))
                    command_str = command_str.replace(
                        "((output_duration))", str(on_duration))
                    command_str = command_str.replace(
                        "((output_pwm))", str(duty_cycle))
                    _, _, cmd_status = cmd_output(command_str)

                    message += u"Status: {}. ".format(cmd_status)

                elif each_cond_action.do_action == 'email':
                    if (self.email_count >= self.smtp_max_count and
                            time.time() < self.smtp_wait_time):
                        self.allowed_to_send_notice = False
                    else:
                        if time.time() > self.smtp_wait_time:
                            self.email_count = 0
                            self.smtp_wait_time = time.time() + 3600
                        self.allowed_to_send_notice = True
                    self.email_count += 1

                    if self.allowed_to_send_notice:
                        message += u"Notify {}.".format(
                            each_cond_action.email_notify)

                        smtp = db_retrieve_table_daemon(SMTP, entry='first')
                        send_email(
                            smtp.host, smtp.ssl, smtp.port, smtp.user,
                            smtp.passw, smtp.email_from,
                            each_cond_action.do_action_string, message)
                    else:
                        self.logger.debug(
                            "[Output Conditional {}] True: {:.0f} seconds "
                            "left to be allowed to email again.".format(
                                each_conditional.id,
                                self.smtp_wait_time-time.time()))

                elif each_cond_action.do_action == 'flash_lcd':
                    start_flashing = threading.Thread(
                        target=self.control.flash_lcd,
                        args=(each_cond_action.do_lcd_id, 1,))
                    start_flashing.start()

                # TODO: Implement photo/video actions for output conditionals
                elif each_cond_action.do_action == 'photo':
                    self.logger.error("Photo action not currently implemented")

                elif each_cond_action.do_action == 'video':
                    self.logger.error("Video action not currently implemented")

                self.logger.debug(u"{}".format(message))
Esempio n. 5
0
    def output_switch(self, output_id, state, duty_cycle=None):
        """Conduct the actual execution of GPIO state change, PWM, or command execution"""
        if self.output_type[output_id] == 'wired':
            if state == 'on':
                GPIO.output(self.output_pin[output_id],
                            self.output_trigger[output_id])
            elif state == 'off':
                GPIO.output(self.output_pin[output_id],
                            not self.output_trigger[output_id])

        elif self.output_type[output_id] == 'wireless_433MHz_pi_switch':
            if state == 'on':
                self.wireless_pi_switch[output_id].transmit(
                    int(self.output_on_command[output_id]))
            elif state == 'off':
                self.wireless_pi_switch[output_id].transmit(
                    int(self.output_off_command[output_id]))

        elif self.output_type[output_id] == 'command':
            if state == 'on' and self.output_on_command[output_id]:
                cmd_return, _, cmd_status = cmd_output(
                    self.output_on_command[output_id])
            elif state == 'off' and self.output_off_command[output_id]:
                cmd_return, _, cmd_status = cmd_output(
                    self.output_off_command[output_id])
            else:
                return
            self.logger.debug(
                u"Output {state} command returned: "
                u"{stat}: '{ret}'".format(
                    state=state,
                    stat=cmd_status,
                    ret=cmd_return))

        elif self.output_type[output_id] == 'pwm':
            if state == 'on':
                if self.pwm_library[output_id] == 'pigpio_hardware':
                    self.pwm_output[output_id].hardware_PWM(
                        self.output_pin[output_id],
                        self.pwm_hertz[output_id],
                        abs(duty_cycle) * 10000)
                elif self.pwm_library[output_id] == 'pigpio_any':
                    self.pwm_output[output_id].set_PWM_frequency(
                        self.output_pin[output_id],
                        self.pwm_hertz[output_id])
                    calc_duty_cycle = int((abs(duty_cycle) / 100.0) * 255)
                    if calc_duty_cycle > 255:
                        calc_duty_cycle = 255
                    if calc_duty_cycle < 0:
                        calc_duty_cycle = 0
                    self.pwm_output[output_id].set_PWM_dutycycle(
                        self.output_pin[output_id],
                        calc_duty_cycle)
                self.pwm_state[output_id] = abs(duty_cycle)
            elif state == 'off':
                if self.pwm_library[output_id] == 'pigpio_hardware':
                    self.pwm_output[output_id].hardware_PWM(
                        self.output_pin[output_id],
                        self.pwm_hertz[output_id], 0)
                elif self.pwm_library[output_id] == 'pigpio_any':
                    self.pwm_output[output_id].set_PWM_frequency(
                        self.output_pin[output_id],
                        self.pwm_hertz[output_id])
                    self.pwm_output[output_id].set_PWM_dutycycle(
                        self.output_pin[output_id], 0)
                self.pwm_state[output_id] = None
Esempio n. 6
0
def send_email(smtp_host, smtp_ssl, smtp_port, smtp_user, smtp_pass,
               smtp_email_from, email_to, message,
               attachment_file=False, attachment_type=False):
    """
    Email a specific recipient or recipients a message.

    :return: success (0) or failure (1)
    :rtype: bool

    :param email_to: Who to email
    :type email_to: str or list
    :param message: Message in the body of the email
    :type message: str
    """
    try:
        if smtp_ssl:
            server = smtplib.SMTP_SSL(smtp_host, smtp_port)
            server.ehlo()
        else:
            server = smtplib.SMTP(smtp_host, smtp_port)
            server.ehlo()
            server.starttls()
        server.login(smtp_user, smtp_pass)
        msg = MIMEMultipart()
        msg['Subject'] = "Mycodo Notification ({})".format(
            socket.gethostname())
        msg['From'] = smtp_email_from
        msg['To'] = email_to
        msg_body = MIMEText(message.decode('utf-8'), 'plain', 'utf-8')
        msg.attach(msg_body)

        if attachment_file and attachment_type == 'still':
            img_data = open(attachment_file, 'rb').read()
            image = MIMEImage(img_data,
                              name=os.path.basename(attachment_file))
            msg.attach(image)
        elif attachment_file and attachment_type == 'video':
            out_filename = '{}-compressed.h264'.format(attachment_file)
            cmd_output(
                'avconv -i "{}" -vf scale=-1:768 -c:v libx264 -preset '
                'veryfast -crf 22 -c:a copy "{}"'.format(
                    attachment_file, out_filename))
            set_user_grp(out_filename, 'mycodo', 'mycodo')
            f = open(attachment_file, 'rb').read()
            video = MIMEBase('application', 'octet-stream')
            video.set_payload(f)
            Encoders.encode_base64(video)
            video.add_header('Content-Disposition',
                             'attachment; filename="{}"'.format(
                                 os.path.basename(attachment_file)))
            msg.attach(video)

        server.sendmail(msg['From'], msg['To'].split(","), msg.as_string())
        server.quit()
        return 0
    except Exception as error:
        if logging:
            logging.exception(
                "Could not send email to {add} with message: {msg}. Error: "
                "{err}".format(add=email_to, msg=message, err=error))
        return 1
Esempio n. 7
0
    def checkConditionals(self, relay_id, on_duration):
        with session_scope(MYCODO_DB_PATH) as new_session:
            conditionals = new_session.query(RelayConditional)
            new_session.expunge_all()
            new_session.close()

        conditionals = conditionals.filter(RelayConditional.if_relay_id == relay_id)
        conditionals = conditionals.filter(RelayConditional.activated == True)

        if self.is_on(relay_id):
            conditionals = conditionals.filter(RelayConditional.if_action == 'on')
            conditionals = conditionals.filter(RelayConditional.if_duration == on_duration)
        else:
            conditionals = conditionals.filter(RelayConditional.if_action == 'off')

        for each_conditional in conditionals.all():
            message = None
            if (each_conditional.do_relay_id or
                    each_conditional.execute_command or
                    each_conditional.email_notify):
                now = time.time()
                timestamp = datetime.datetime.fromtimestamp(now).strftime('%Y-%m-%d %H-%M-%S')
                message = "{}\n[Relay Conditional {}] {}\n".format(
                    timestamp, each_conditional.id, each_conditional.name)
                message += "If relay {} ({}) turns {}, Then:\n".format(
                    each_conditional.if_relay_id,
                    self.relay_name[each_conditional.if_relay_id],
                    each_conditional.if_action)

            if each_conditional.do_relay_id:
                message += "Turn relay {} ({}) {}".format(
                        each_conditional.do_relay_id,
                        self.relay_name[each_conditional.do_relay_id],
                        each_conditional.do_action)

                if each_conditional.do_duration == 0:
                    self.relay_on_off(each_conditional.do_relay_id,
                                      each_conditional.do_action)
                else:
                    message += " for {} seconds".format(each_conditional.do_duration)
                    self.relay_on_off(each_conditional.do_relay_id,
                                      each_conditional.do_action,
                                      each_conditional.do_duration)
                message += ".\n"

            if each_conditional.execute_command:
                # Execute command as user mycodo
                message += "Execute: '{}'. ".format(
                    each_conditional.execute_command)
                cmd_out, cmd_err, cmd_status = cmd_output(
                    self.cond_execute_command[cond_id])
                message += "Status: {}. ".format(cmd_status)

            if each_conditional.email_notify:
                if (self.email_count >= self.smtp_max_count and
                        time.time() < self.smtp_wait_time):
                     self.allowed_to_send_notice = False
                else:
                    if time.time() > self.smtp_wait_time:
                        self.email_count = 0
                        self.smtp_wait_time = time.time() + 3600
                    self.allowed_to_send_notice = True
                self.email_count += 1

                if self.allowed_to_send_notice:
                    message += "Notify {}.".format(
                        each_conditional.email_notify)

                    with session_scope(MYCODO_DB_PATH) as new_session:
                        smtp = new_session.query(SMTP).first()
                        send_email(self.logger, smtp.host, smtp.ssl, smtp.port,
                              smtp.user, smtp.passw, smtp.email_from,
                              each_conditional.email_notify, message)
                else:
                    self.logger.debug("[Relay Conditional {}] True: "
                                      "{:.0f} seconds left to be "
                                      "allowed to email again.".format(
                                      each_cond.id,
                                      (self.smtp_wait_time-time.time())))

            if each_conditional.flash_lcd:
                start_flashing = threading.Thread(
                    target=self.control.flash_lcd,
                    args=(each_conditional.flash_lcd,
                          1,))
                start_flashing.start()

            if (each_conditional.do_relay_id or
                    each_conditional.execute_command or
                    each_conditional.email_notify):
                self.logger.debug("{}".format(message))
Esempio n. 8
0
    def check_conditionals(self, relay_id, on_duration):
        conditionals = db_retrieve_table_daemon(Conditional)
        conditionals = conditionals.filter(
            Conditional.if_relay_id == relay_id)
        conditionals = conditionals.filter(
            Conditional.is_activated == True)

        if self.is_on(relay_id):
            conditionals = conditionals.filter(
                Conditional.if_relay_state == 'on')
            conditionals = conditionals.filter(
                Conditional.if_relay_duration == on_duration)
        else:
            conditionals = conditionals.filter(
                Conditional.if_relay_state == 'off')

        for each_conditional in conditionals.all():
            conditional_actions = db_retrieve_table_daemon(ConditionalActions)
            conditional_actions = conditional_actions.filter(
                ConditionalActions.conditional_id == each_conditional.id).all()

            for each_cond_action in conditional_actions:
                now = time.time()
                timestamp = datetime.datetime.fromtimestamp(now).strftime('%Y-%m-%d %H-%M-%S')
                message = u"{ts}\n[Relay Conditional {id}] {name}\n".format(
                    ts=timestamp,
                    id=each_cond_action.id,
                    name=each_conditional.name)

                if each_cond_action.do_action == 'relay':
                    if each_cond_action.do_relay_id not in self.relay_name:
                        message += u"Error: Invalid relay ID {id}.".format(
                            id=each_cond_action.do_relay_id)
                    else:
                        message += u"If relay {id} ({name}) turns {state}, Then ".format(
                            id=each_conditional.if_relay_id,
                            name=self.relay_name[each_conditional.if_relay_id],
                            state=each_conditional.if_relay_state)
                        message += u"turn relay {id} ({name}) {state}".format(
                            id=each_cond_action.do_relay_id,
                            name=self.relay_name[each_cond_action.do_relay_id],
                            state=each_cond_action.do_relay_state)

                        if each_cond_action.do_relay_duration == 0:
                            self.relay_on_off(each_cond_action.do_relay_id,
                                              each_cond_action.do_relay_state)
                        else:
                            message += u" for {dur} seconds".format(
                                dur=each_cond_action.do_relay_duration)
                            self.relay_on_off(each_cond_action.do_relay_id,
                                              each_cond_action.do_relay_state,
                                              duration=each_cond_action.do_relay_duration)
                    message += ".\n"

                elif each_cond_action.do_action == 'command':
                    # Execute command as user mycodo
                    message += u"Execute: '{}'. ".format(
                        each_cond_action.do_action_string)
                    _, _, cmd_status = cmd_output(
                        each_cond_action.do_action_string)
                    message += u"Status: {}. ".format(cmd_status)

                elif each_cond_action.do_action == 'email':
                    if (self.email_count >= self.smtp_max_count and
                            time.time() < self.smtp_wait_time):
                        self.allowed_to_send_notice = False
                    else:
                        if time.time() > self.smtp_wait_time:
                            self.email_count = 0
                            self.smtp_wait_time = time.time() + 3600
                        self.allowed_to_send_notice = True
                    self.email_count += 1

                    if self.allowed_to_send_notice:
                        message += u"Notify {}.".format(
                            each_cond_action.email_notify)

                        smtp = db_retrieve_table_daemon(SMTP, entry='first')
                        send_email(
                            smtp.host, smtp.ssl, smtp.port, smtp.user,
                            smtp.passw, smtp.email_from,
                            each_cond_action.do_action_string, message)
                    else:
                        self.logger.debug(
                            "[Relay Conditional {}] True: {:.0f} seconds "
                            "left to be allowed to email again.".format(
                                each_conditional.id,
                                self.smtp_wait_time-time.time()))

                elif each_cond_action.do_action == 'flash_lcd':
                    start_flashing = threading.Thread(
                        target=self.control.flash_lcd,
                        args=(each_cond_action.do_lcd_id, 1,))
                    start_flashing.start()

                # TODO: Implement photo/video actions for relay conditionals
                elif each_cond_action.do_action == 'photo':
                    pass

                elif each_cond_action.do_action == 'video':
                    pass

                self.logger.debug(u"{}".format(message))
Esempio n. 9
0
    def relay_switch(self, relay_id, state, duty_cycle=None):
        if self.relay_type[relay_id] == 'wired':
            if state == 'on':
                GPIO.output(self.relay_pin[relay_id],
                            self.relay_trigger[relay_id])
            elif state == 'off':
                GPIO.output(self.relay_pin[relay_id],
                            not self.relay_trigger[relay_id])

        elif self.relay_type[relay_id] == 'wireless_433MHz_pi_switch':
            if state == 'on':
                self.wireless_pi_switch[relay_id].transmit(
                    int(self.relay_on_command[relay_id]))
            elif state == 'off':
                self.wireless_pi_switch[relay_id].transmit(
                    int(self.relay_off_command[relay_id]))

        elif self.relay_type[relay_id] == 'command':
            if state == 'on' and self.relay_on_command[relay_id]:
                cmd_return, _, cmd_status = cmd_output(
                    self.relay_on_command[relay_id])
            elif state == 'off' and self.relay_off_command[relay_id]:
                cmd_return, _, cmd_status = cmd_output(
                    self.relay_off_command[relay_id])
            else:
                return
            self.logger.debug(
                u"Relay {state} command returned: "
                u"{stat}: '{ret}'".format(
                    state=state,
                    stat=cmd_status,
                    ret=cmd_return))

        elif self.relay_type[relay_id] == 'pwm':
            if state == 'on':
                if self.pwm_library[relay_id] == 'pigpio_hardware':
                    self.pwm_output[relay_id].hardware_PWM(
                        self.relay_pin[relay_id],
                        self.pwm_hertz[relay_id],
                        abs(duty_cycle) * 10000)
                elif self.pwm_library[relay_id] == 'pigpio_any':
                    self.pwm_output[relay_id].set_PWM_frequency(
                        self.relay_pin[relay_id],
                        self.pwm_hertz[relay_id])
                    calc_duty_cycle = int((abs(duty_cycle) / 100.0) * 255)
                    if calc_duty_cycle > 255:
                        calc_duty_cycle = 255
                    if calc_duty_cycle < 0:
                        calc_duty_cycle = 0
                    self.pwm_output[relay_id].set_PWM_dutycycle(
                        self.relay_pin[relay_id],
                        calc_duty_cycle)
                self.pwm_state[relay_id] = abs(duty_cycle)
            elif state == 'off':
                if self.pwm_library[relay_id] == 'pigpio_hardware':
                    self.pwm_output[relay_id].hardware_PWM(
                        self.relay_pin[relay_id],
                        self.pwm_hertz[relay_id], 0)
                elif self.pwm_library[relay_id] == 'pigpio_any':
                    self.pwm_output[relay_id].set_PWM_frequency(
                        self.relay_pin[relay_id],
                        self.pwm_hertz[relay_id])
                    self.pwm_output[relay_id].set_PWM_dutycycle(
                        self.relay_pin[relay_id], 0)
                self.pwm_state[relay_id] = None
Esempio n. 10
0
    def check_conditionals(self, cond_id):
        """
        Check if any sensor conditional statements are activated and
        execute their actions if the conditional is true.

        For example, if measured temperature is above 30C, notify [email protected]

        :rtype: None

        :param cond_id: ID of conditional to check
        :type cond_id: str
        """
        logger_cond = logging.getLogger(
            "mycodo.SensorCond-{id}".format(id=cond_id))
        attachment_file = False
        attachment_type = False
        message = ""

        conditional = False
        if self.cond_edge_detected[cond_id]:
            conditional = 'edge'
        elif self.cond_direction[cond_id]:
            conditional = 'measurement'

        now = time.time()
        timestamp = datetime.datetime.fromtimestamp(now).strftime(
            '%Y-%m-%d %H-%M-%S')

        if conditional == 'measurement':
            last_measurement = self.get_last_measurement(
                self.cond_measurement_type[cond_id])
            if (last_measurement and
                ((self.cond_direction[cond_id] == 'above'
                  and last_measurement > self.cond_setpoint[cond_id]) or
                 (self.cond_direction[cond_id] == 'below'
                  and last_measurement < self.cond_setpoint[cond_id]))):

                message = "{}\n[Sensor Conditional {}] {}\n{} {} ".format(
                    timestamp, cond_id, self.cond_name[cond_id],
                    self.cond_measurement_type[cond_id], last_measurement)
                if self.cond_direction[cond_id] == 'above':
                    message += ">"
                elif self.cond_direction[cond_id] == 'below':
                    message += "<"
                message += " {} setpoint.".format(self.cond_setpoint[cond_id])
            else:
                logger_cond.debug("Last measurement not found")
                return 1

        elif conditional == 'edge':
            if self.cond_edge_select[cond_id] == 'edge':
                message = "{}\n[Sensor Conditional {}] {}. {} Edge Detected.".format(
                    timestamp, cond_id, self.cond_name[cond_id],
                    self.cond_edge_detected)
            elif self.cond_edge_select[cond_id] == 'state':
                if GPIO.input(int(
                        self.location)) == self.cond_gpio_state[cond_id]:
                    message = "{}\n[Sensor Conditional {}] {}. {} GPIO State Detected.".format(
                        timestamp, cond_id, self.cond_name[cond_id],
                        self.cond_gpio_state[cond_id])
                else:
                    return 0

        if (self.cond_relay_id[cond_id]
                and self.cond_relay_state[cond_id] in ['on', 'off']):
            message += "\nTurning relay {} {}".format(
                self.cond_relay_id[cond_id], self.cond_relay_state[cond_id])
            if (self.cond_relay_state[cond_id] == 'on'
                    and self.cond_relay_on_duration[cond_id]):
                message += " for {} seconds".format(
                    self.cond_relay_on_duration[cond_id])
            message += ". "
            relay_on_off = threading.Thread(
                target=self.control.relay_on_off,
                args=(
                    self.cond_relay_id[cond_id],
                    self.cond_relay_state[cond_id],
                    self.cond_relay_on_duration[cond_id],
                ))
            relay_on_off.start()

        # Execute command in shell
        if self.cond_execute_command[cond_id]:
            message += "\nExecute '{}'. ".format(
                self.cond_execute_command[cond_id])
            _, _, cmd_status = cmd_output(self.cond_execute_command[cond_id])
            message += "Status: {}. ".format(cmd_status)

        if self.cond_camera_record[cond_id] in ['photo', 'photoemail']:
            camera_still = db_retrieve_table(MYCODO_DB_PATH,
                                             CameraStill,
                                             entry='first')
            attachment_file = camera_record('photo', camera_still)
        elif self.cond_camera_record[cond_id] in ['video', 'videoemail']:
            camera_stream = db_retrieve_table(MYCODO_DB_PATH,
                                              CameraStream,
                                              entry='first')
            attachment_file = camera_record('video',
                                            camera_stream,
                                            duration_sec=5)

        if self.cond_email_notify[cond_id]:
            if (self.email_count >= self.smtp_max_count
                    and time.time() < self.smtp_wait_timer[cond_id]):
                self.allowed_to_send_notice = False
            else:
                if time.time() > self.smtp_wait_timer[cond_id]:
                    self.email_count = 0
                    self.smtp_wait_timer[cond_id] = time.time() + 3600
                self.allowed_to_send_notice = True
            self.email_count += 1

            # If the emails per hour limit has not been exceeded
            if self.allowed_to_send_notice:
                message += "\nNotify {}.".format(
                    self.cond_email_notify[cond_id])
                # attachment_type != False indicates to
                # attach a photo or video
                if self.cond_camera_record[cond_id] == 'photoemail':
                    message += "\nPhoto attached."
                    attachment_type = 'still'
                elif self.cond_camera_record[cond_id] == 'videoemail':
                    message += "\nVideo attached."
                    attachment_type = 'video'

                smtp = db_retrieve_table(MYCODO_DB_PATH, SMTP, entry='first')
                send_email(smtp.host, smtp.ssl, smtp.port, smtp.user,
                           smtp.passw, smtp.email_from,
                           self.cond_email_notify[cond_id], message,
                           attachment_file, attachment_type)
            else:
                logger_cond.debug(
                    "{:.0f} seconds left to be allowed to email "
                    "again.".format(self.smtp_wait_timer[cond_id] -
                                    time.time()))

        if self.cond_flash_lcd[cond_id]:
            start_flashing = threading.Thread(target=self.control.flash_lcd,
                                              args=(
                                                  self.cond_flash_lcd[cond_id],
                                                  1,
                                              ))
            start_flashing.start()

        logger_cond.debug(message)
Esempio n. 11
0
    def check_conditionals(self, cond_id):
        """
        Check if any sensor conditional statements are activated and
        execute their actions if the conditional is true.

        For example, if measured temperature is above 30C, notify [email protected]

        :rtype: None

        :param cond_id: ID of conditional to check
        :type cond_id: str
        """
        logger_cond = logging.getLogger(
            "mycodo.sensor_cond_{id}".format(id=cond_id))
        attachment_file = False
        attachment_type = False

        cond = db_retrieve_table_daemon(Conditional,
                                        device_id=cond_id,
                                        entry='first')

        message = u"[Sensor Conditional: {name} ({id})]".format(name=cond.name,
                                                                id=cond_id)

        if cond.if_sensor_direction:
            last_measurement = self.get_last_measurement(
                cond.if_sensor_measurement)
            if (last_measurement
                    and ((cond.if_sensor_direction == 'above'
                          and last_measurement > cond.if_sensor_setpoint) or
                         (cond.if_sensor_direction == 'below'
                          and last_measurement < cond.if_sensor_setpoint))):

                message += u" {meas}: {value} ".format(
                    meas=cond.if_sensor_measurement, value=last_measurement)
                if cond.if_sensor_direction == 'above':
                    message += "(>"
                elif cond.if_sensor_direction == 'below':
                    message += "(<"
                message += u" {sp} set value).".format(
                    sp=cond.if_sensor_setpoint)
            else:
                logger_cond.debug("Last measurement not found")
                return 1
        elif cond.if_sensor_edge_detected:
            if cond.if_sensor_edge_select == 'edge':
                message += u" {edge} Edge Detected.".format(
                    edge=cond.if_sensor_edge_detected)
            elif cond.if_sensor_edge_select == 'state':
                if GPIO.input(int(self.location)) == cond.if_sensor_gpio_state:
                    message += u" {state} GPIO State Detected.".format(
                        state=cond.if_sensor_gpio_state)
                else:
                    return 0

        cond_actions = db_retrieve_table_daemon(ConditionalActions)
        cond_actions = cond_actions.filter(
            ConditionalActions.conditional_id == cond_id).all()

        for cond_action in cond_actions:
            message += u" Conditional Action ({id}): {do_action}.".format(
                id=cond_action.id, do_action=cond_action.do_action)

            # Actuate relay
            if (cond_action.do_relay_id
                    and cond_action.do_relay_state in ['on', 'off']):
                message += u" Turn relay {id} {state}".format(
                    id=cond_action.do_relay_id,
                    state=cond_action.do_relay_state)
                if (cond_action.do_relay_state == 'on'
                        and cond_action.do_relay_duration):
                    message += u" for {sec} seconds".format(
                        sec=cond_action.do_relay_duration)
                message += "."
                relay_on_off = threading.Thread(
                    target=self.control.relay_on_off,
                    args=(
                        cond_action.do_relay_id,
                        cond_action.do_relay_state,
                        cond_action.do_relay_duration,
                    ))
                relay_on_off.start()

            # Execute command in shell
            elif cond_action.do_action == 'command':
                message += u" Execute '{com}' ".format(
                    com=cond_action.do_action_string)
                _, _, cmd_status = cmd_output(cond_action.do_action_string)
                message += u"(Status: {stat}).".format(stat=cmd_status)

            # Capture photo
            elif cond_action.do_action in ['photo', 'photo_email']:
                message += u"  Capturing photo with camera ({id}).".format(
                    id=cond_action.do_camera_id)
                camera_still = db_retrieve_table_daemon(
                    Camera, device_id=cond_action.do_camera_id)
                attachment_file = camera_record('photo', camera_still)

            # Capture video
            elif cond_action.do_action in ['video', 'video_email']:
                message += u"  Capturing video with camera ({id}).".format(
                    id=cond_action.do_camera_id)
                camera_stream = db_retrieve_table_daemon(
                    Camera, device_id=cond_action.do_camera_id)
                attachment_file = camera_record(
                    'video',
                    camera_stream,
                    duration_sec=cond_action.do_camera_duration)

            # Activate PID controller
            elif cond_action.do_action == 'activate_pid':
                message += u" Activate PID ({id}).".format(
                    id=cond_action.do_pid_id)
                pid = db_retrieve_table_daemon(PID,
                                               device_id=cond_action.do_pid_id,
                                               entry='first')
                if pid.is_activated:
                    message += u" Notice: PID is already active!"
                else:
                    activate_pid = threading.Thread(
                        target=self.control.controller_activate,
                        args=(
                            'PID',
                            cond_action.do_pid_id,
                        ))
                    activate_pid.start()

            # Deactivate PID controller
            elif cond_action.do_action == 'deactivate_pid':
                message += u" Deactivate PID ({id}).".format(
                    id=cond_action.do_pid_id)
                pid = db_retrieve_table_daemon(PID,
                                               device_id=cond_action.do_pid_id,
                                               entry='first')
                if not pid.is_activated:
                    message += u" Notice: PID is already inactive!"
                else:
                    deactivate_pid = threading.Thread(
                        target=self.control.controller_deactivate,
                        args=(
                            'PID',
                            cond_action.do_pid_id,
                        ))
                    deactivate_pid.start()

            elif cond_action.do_action in [
                    'email', 'photo_email', 'video_email'
            ]:
                if (self.email_count >= self.smtp_max_count
                        and time.time() < self.smtp_wait_timer[cond_id]):
                    self.allowed_to_send_notice = False
                else:
                    if time.time() > self.smtp_wait_timer[cond_id]:
                        self.email_count = 0
                        self.smtp_wait_timer[cond_id] = time.time() + 3600
                    self.allowed_to_send_notice = True
                self.email_count += 1

                # If the emails per hour limit has not been exceeded
                if self.allowed_to_send_notice:
                    message += u" Notify {email}.".format(
                        email=cond_action.do_action_string)
                    # attachment_type != False indicates to
                    # attach a photo or video
                    if cond_action.do_action == 'photo_email':
                        message += u" Photo attached to email."
                        attachment_type = 'still'
                    elif cond_action.do_action == 'video_email':
                        message += u" Video attached to email."
                        attachment_type = 'video'

                    smtp = db_retrieve_table_daemon(SMTP, entry='first')
                    send_email(smtp.host, smtp.ssl, smtp.port, smtp.user,
                               smtp.passw, smtp.email_from,
                               cond_action.do_action_string, message,
                               attachment_file, attachment_type)
                else:
                    logger_cond.debug(
                        "Wait {sec:.0f} seconds to email again.".format(
                            sec=self.smtp_wait_timer[cond_id] - time.time()))

            elif cond_action.do_action == 'flash_lcd':
                message += u" Flashing LCD ({id}).".format(
                    id=cond_action.do_lcd_id)
                start_flashing = threading.Thread(
                    target=self.control.flash_lcd,
                    args=(
                        cond_action.do_lcd_id,
                        1,
                    ))
                start_flashing.start()

        logger_cond.debug(message)
Esempio n. 12
0
    def checkConditionals(self, relay_id, on_duration):
        with session_scope(MYCODO_DB_PATH) as new_session:
            conditionals = new_session.query(RelayConditional)
            new_session.expunge_all()
            new_session.close()

        conditionals = conditionals.filter(
            RelayConditional.if_relay_id == relay_id)
        conditionals = conditionals.filter(RelayConditional.activated == True)

        if self.is_on(relay_id):
            conditionals = conditionals.filter(
                RelayConditional.if_action == 'on')
            conditionals = conditionals.filter(
                RelayConditional.if_duration == on_duration)
        else:
            conditionals = conditionals.filter(
                RelayConditional.if_action == 'off')

        for each_conditional in conditionals.all():
            message = None
            if (each_conditional.do_relay_id
                    or each_conditional.execute_command
                    or each_conditional.email_notify):
                now = time.time()
                timestamp = datetime.datetime.fromtimestamp(now).strftime(
                    '%Y-%m-%d %H-%M-%S')
                message = "{}\n[Relay Conditional {}] {}\n".format(
                    timestamp, each_conditional.id, each_conditional.name)
                message += "If relay {} ({}) turns {}, Then:\n".format(
                    each_conditional.if_relay_id,
                    self.relay_name[each_conditional.if_relay_id],
                    each_conditional.if_action)

            if each_conditional.do_relay_id:
                message += "Turn relay {} ({}) {}".format(
                    each_conditional.do_relay_id,
                    self.relay_name[each_conditional.do_relay_id],
                    each_conditional.do_action)

                if each_conditional.do_duration == 0:
                    self.relay_on_off(each_conditional.do_relay_id,
                                      each_conditional.do_action)
                else:
                    message += " for {} seconds".format(
                        each_conditional.do_duration)
                    self.relay_on_off(each_conditional.do_relay_id,
                                      each_conditional.do_action,
                                      each_conditional.do_duration)
                message += ".\n"

            if each_conditional.execute_command:
                # Execute command as user mycodo
                message += "Execute: '{}'. ".format(
                    each_conditional.execute_command)
                cmd_out, cmd_err, cmd_status = cmd_output(
                    self.cond_execute_command[cond_id])
                message += "Status: {}. ".format(cmd_status)

            if each_conditional.email_notify:
                if (self.email_count >= self.smtp_max_count
                        and time.time() < self.smtp_wait_time):
                    self.allowed_to_send_notice = False
                else:
                    if time.time() > self.smtp_wait_time:
                        self.email_count = 0
                        self.smtp_wait_time = time.time() + 3600
                    self.allowed_to_send_notice = True
                self.email_count += 1

                if self.allowed_to_send_notice:
                    message += "Notify {}.".format(
                        each_conditional.email_notify)

                    with session_scope(MYCODO_DB_PATH) as new_session:
                        smtp = new_session.query(SMTP).first()
                        send_email(self.logger, smtp.host, smtp.ssl, smtp.port,
                                   smtp.user, smtp.passw, smtp.email_from,
                                   each_conditional.email_notify, message)
                else:
                    self.logger.debug("[Relay Conditional {}] True: "
                                      "{:.0f} seconds left to be "
                                      "allowed to email again.".format(
                                          each_cond.id,
                                          (self.smtp_wait_time - time.time())))

            if each_conditional.flash_lcd:
                start_flashing = threading.Thread(
                    target=self.control.flash_lcd,
                    args=(
                        each_conditional.flash_lcd,
                        1,
                    ))
                start_flashing.start()

            if (each_conditional.do_relay_id
                    or each_conditional.execute_command
                    or each_conditional.email_notify):
                self.logger.debug("{}".format(message))
Esempio n. 13
0
    def checkConditionals(self, cond_id):
        """
        Check if any sensor conditional statements are activated and
        execute their actions if the conditional is true.

        For example, if measured temperature is above 30C, notify [email protected]

        :rtype: None

        :param each_cond: Object of SQL table entries for a specific column
        :type each_cond: sqlalchemy object
        """
        attachment_file = False
        attachment_type = False
        message = ""

        conditional = False
        if self.cond_edge_detected[cond_id]:
            conditional = 'edge'
        elif self.cond_direction[cond_id]:
            conditional = 'measurement'

        now = time.time()
        timestamp = datetime.datetime.fromtimestamp(now).strftime('%Y-%m-%d %H-%M-%S')

        if conditional == 'measurement':
            last_measurement = self.getLastMeasurement(self.cond_measurement_type[cond_id])
            if (last_measurement and
                ((self.cond_direction[cond_id] == 'above' and
                    last_measurement > self.cond_setpoint[cond_id]) or
                (self.cond_direction[cond_id] == 'below' and
                    last_measurement < self.cond_setpoint[cond_id]))):

                message = "{}\n[Sensor Conditional {}] {}\n{} {} ".format(
                        timestamp, cond_id,
                        self.cond_name[cond_id],
                        self.cond_measurement_type[cond_id],
                        last_measurement)
                if self.cond_direction[cond_id] == 'above':
                    message += ">"
                elif self.cond_direction[cond_id] == 'below':
                    message += "<"
                message += " {} setpoint.".format(self.cond_setpoint[cond_id])
            else:
                self.logger.debug("[Sensor Conditional {}] Last measurement "
                                  "not found".format(cond_id))
                return 1

        elif conditional == 'edge':
            if self.cond_edge_select[cond_id] == 'edge':
                message = "{}\n[Sensor Conditional {}] {}. {} Edge Detected.".format(
                    timestamp, cond_id,
                    self.cond_name[cond_id],
                    self.cond_edge_detected)
            elif self.cond_edge_select[cond_id] == 'state':
                if GPIO.input(int(self.location)) == self.cond_gpio_state[cond_id]:
                    message = "{}\n[Sensor Conditional {}] {}. {} GPIO State Detected.".format(
                        timestamp, cond_id,
                        self.cond_name[cond_id],
                        self.cond_gpio_state[cond_id])
                else:
                    return 0

        if (self.cond_relay_id[cond_id] and
                self.cond_relay_state[cond_id] in ['on', 'off']):
            message += "\nTurning relay {} {}".format(
                    self.cond_relay_id[cond_id],
                    self.cond_relay_state[cond_id])
            if (self.cond_relay_state[cond_id] == 'on' and
                    self.cond_relay_on_duration[cond_id]):
                message += " for {} seconds".format(self.cond_relay_on_duration[cond_id])
            message += ". "
            relay_on_off = threading.Thread(
                target=self.control.relay_on_off,
                args=(self.cond_relay_id[cond_id],
                      self.cond_relay_state[cond_id],
                      self.cond_relay_on_duration[cond_id],))
            relay_on_off.start()

        # Execute command in shell
        if self.cond_execute_command[cond_id]:
            message += "\nExecute '{}'. ".format(
                    self.cond_execute_command[cond_id])
            cmd_out, cmd_err, cmd_status = cmd_output(self.cond_execute_command[cond_id])
            message += "Status: {}. ".format(cmd_status)

        if self.cond_camera_record[cond_id] in ['photo', 'photoemail']:
            attachment_file = camera_record(INSTALL_DIRECTORY, 'photo')
        elif self.cond_camera_record[cond_id] in ['video', 'videoemail']:
            attachment_file = camera_record(INSTALL_DIRECTORY, 'video', duration_sec=5)

        if self.cond_email_notify[cond_id]:
            if (self.email_count >= self.smtp_max_count and
                    time.time() < self.smtp_wait_timer[cond_id]):
                 self.allowed_to_send_notice = False
            else:
                if time.time() > self.smtp_wait_timer[cond_id]:
                    self.email_count = 0
                    self.smtp_wait_timer[cond_id] = time.time()+3600
                self.allowed_to_send_notice = True
            self.email_count += 1

            # If the emails per hour limit has not been exceeded
            if self.allowed_to_send_notice:
                message += "\nNotify {}.".format(
                        self.cond_email_notify[cond_id])
                # attachment_type != False indicates to
                # attach a photo or video
                if self.cond_camera_record[cond_id] == 'photoemail':
                    message += "\nPhoto attached."
                    attachment_type = 'still'
                elif self.cond_camera_record[cond_id] == 'videoemail':
                    message += "\nVideo attached."
                    attachment_type = 'video'
                with session_scope(MYCODO_DB_PATH) as new_session:
                    smtp = new_session.query(SMTP).first()
                    send_email(self.logger, smtp.host, smtp.ssl, smtp.port,
                          smtp.user, smtp.passw, smtp.email_from,
                          self.cond_email_notify[cond_id], message,
                          attachment_file, attachment_type)
            else:
                self.logger.debug("[Sensor Conditional {}] "
                                  "{:.0f} seconds left to be "
                                  "allowed to email again.".format(
                                  cond_id,
                                  (self.smtp_wait_timer[cond_id]-time.time())))

        if self.cond_flash_lcd[cond_id]:
            start_flashing = threading.Thread(
                target=self.control.flash_lcd,
                args=(self.cond_flash_lcd[cond_id],
                      1,))
            start_flashing.start()

        self.logger.debug(message)