예제 #1
0
    def snmp_agent_start():
        """
        Starts SNMP agent
        """
        from server.snmp import agent

        # SNMP agent must be placed in thread rather than
        # multiprocess process because dynamic variables are
        # shared between main process and the agent
        obj_snmpa = agent.SNMPAgent()
        try:
            th_snmpa = threading.Thread(
                target=obj_snmpa.engine,
                args=()
            )
            th_snmpa.start()
            MPQ_STAT.put_nowait([
                'snmp_notify',
                th_snmpa.ident
            ])

        except threading.ThreadError:
            log = 'Could not start SNMP agent due to threading error.'
            logger.exception(log)
            MPQ_ACT.put_nowait([
                datetime.now().isoformat(' '),
                'CRITICAL',
                log
            ])
            MPQ_STAT.put_nowait([
                'snmp_notify',
                False
            ])
예제 #2
0
    def on_close(
        self,
        reason
    ):
        """
        Processes to execute when websocket closes
        """
        # Ensure that multiprocess process is terminated
        if self.mp_ws_listener is not None:
            if self.mp_ws_listener.is_alive():
                self.mp_ws_listener_stop.put_nowait(None)
                time.sleep(0.1)
                if self.mp_ws_listener.is_alive():
                    self.mp_ws_listener.join()

        # Update base_pid document in CouchDB config database
        data_cdb_out, stat_cdb, http_cdb = dbase.cdb_request(
            cdb_cmd='upd_doc',
            cdb_name='config',
            cdb_doc='base_pid',
            data_cdb_in={'websocket_handler': False},
            logfile=logfile
        )

        if stat_cdb:
            log = 'Could not update websocket PID values in process status document due to CouchDB error.'
            logger.warning(log)

        MPQ_STAT.put_nowait([
            'websocket',
            False
        ])
예제 #3
0
    def notify(self, mib_identity: str, mib_object: dict, notify_msg: dict):
        """
        Dispatches prebuilt mib object

        :param mib_identity: str
        :param mib_object: dict
        :param notify_msg: dict
        """
        log = notify_msg['start']
        logger.debug(log)
        MPQ_ACT.put_nowait([datetime.now().isoformat(' '), 'INFO', log])

        error_indication, error_status, error_index, var_binds = next(
            sendNotification(
                SnmpEngine(), CommunityData(self.host_community),
                UdpTransportTarget((self.host_ip, self.host_port)),
                ContextData(), 'inform',
                NotificationType(ObjectIdentity(
                    'JANUSESS-MIB', mib_identity + 'Notify').addMibSource(
                        '/opt/Janus/ESS/python3/server/snmp/mibs'),
                                 objects=mib_object)))

        if error_indication:
            log = notify_msg['error'] + str(error_indication)
            logger.warning(log)
            print(log)
            MPQ_ACT.put_nowait([datetime.now().isoformat(' '), 'WARNING', log])
            MPQ_STAT.put_nowait(['base', ['snmp_notify', STAT_LVL['op_err']]])

        else:
            log = notify_msg['end']
            logger.info(log)
            print(log)
            MPQ_ACT.put_nowait([datetime.now().isoformat(' '), 'INFO', log])
            MPQ_STAT.put_nowait(['base', ['snmp_notify', STAT_LVL['op']]])
예제 #4
0
    def poll_clear(self):
        """
        Clears operation polling CouchDB

        self.args[0] = addr_ln
        """
        logfile = 'polling'
        logger = logging.getLogger(logfile)

        log = 'Attempting to clear lane {0} '.format(self.args[0]) +\
              'poll data from polling database.'
        logger.debug(log)
        MPQ_ACT.put_nowait([
            datetime.now().isoformat(' '),
            'DEBUG',
            log
        ])

        # Build and issue InfluxDB command to delete pertinent data
        data_idb_in = 'q=DROP SERIES WHERE "chan"=\'{0}\''.format(self.args[0])
        http_resp = requests.post(
            'http://localhost:8086/query?db=JanusESS',
            headers={'Content-type': 'application/x-www-form-urlencoded'},
            data=data_idb_in
        )

        # Determine result of command and issue status
        if http_resp.status_code == 200:
            log = 'Clear lane {0} poll data successful.'.\
                  format(self.args[0])
            logger.info(log)
            MPQ_ACT.put_nowait([
                datetime.now().isoformat(' '),
                'INFO',
                log
            ])
            MPQ_STAT.put_nowait([
                'base',
                [
                    'influxdb',
                    STAT_LVL['op']
                ]
            ])
        else:
            log = 'Could not clear lane {0} poll data due '.format(self.args[0]) +\
                  'to InfluxDB query error.'
            logger.warning(log)
            MPQ_ACT.put_nowait([
                datetime.now().isoformat(' '),
                'WARNING',
                log
            ])
            MPQ_STAT.put_nowait([
                'base',
                [
                    'influxdb',
                    STAT_LVL['op_err']
                ]
            ])
예제 #5
0
    def i2c_lane_set(self,
                     addr_ln: int,
                     stat_en: bool = True,
                     attempts: int = 3):
        """
        Sets lane for I2C network

        :param addr_ln: int
        :param stat_en: bool
        :param attempts: int

        :return stat_iface: STAT_LVL['op'] or STAT_LVL['crit']
        """
        attempt = 0
        err_iface = False
        stat_iface = STAT_LVL['op']

        # Cycle through attempts
        if addr_ln != self.addr_ln:

            for attempt in range(1, (attempts + 1)):
                err_iface = self.obj_janus.i2c_set_lane(addr_ln=addr_ln)

                if err_iface:
                    err_iface = True
                    if stat_en:
                        MPQ_STAT.put_nowait(
                            ['base', ['interface', STAT_LVL['op_err']]])

                    # Only log warning on last attempt, keeps log clean
                    if attempt == attempts:
                        log = 'Attempt {0} of {1} to '.format(attempt, attempts) + \
                              'set interface to lane {0} failed.'.format(addr_ln)
                        logger.warning(log)
                        MPQ_ACT.put_nowait(
                            [datetime.now().isoformat(' '), 'WARNING', log])

                else:
                    err_iface = False
                    self.addr_ln = addr_ln
                    break

        if err_iface:
            stat_iface = STAT_LVL['op_err']
            if stat_en:
                MPQ_STAT.put_nowait(['base', ['interface', stat_iface]])
            log = 'Set lane {0} on four port interface failed.'.format(addr_ln)
            logger.critical(log)

        else:
            log = 'Set lane {0} on four port interface succeeded after {1} attempts.'. \
                format(addr_ln, attempt)
            logger.info(log)

        return stat_iface
예제 #6
0
    def interrupt_check_flag(self, attempts: int = 2, stat_en: bool = True):
        """
        Checks GPIO interrupt

        :param attempts: int
        :param stat_en: bool

        :return data_iface_out: int (0/1 if STAT_LVL['op'])
        :return stat_iface: STAT_LVL['op'] or STAT_LVL['crit']
        """
        attempt = 0
        err_iface = True
        stat_iface = STAT_LVL['op']
        data_iface_out = None

        # Cycle through attempts
        for attempt in range(1, (attempts + 1)):

            # There is only one interrupt flag for all four lanes.  Therefore
            # no method exists to isolate which of the four GPIOs were triggered.
            data_iface_out, err_iface = self.obj_janus.interrupt_check_flag()

            if err_iface:
                MPQ_STAT.put_nowait(
                    ['base', ['interface', STAT_LVL['op_err']]])

                # Only log warning on last attempt, keeps log clean
                if attempt == attempts:
                    log = 'Attempt {0} of {1} to '.format(attempt, attempts) + \
                          'check GPIO interrupt flag failed.'
                    logger.warning(log)
                    MPQ_ACT.put_nowait(
                        [datetime.now().isoformat(' '), 'WARNING', log])
            else:
                break

        if err_iface:
            log = 'General IO failure to check GPIO interrupt flag.'
            logger.critical(log)
            MPQ_ACT.put_nowait(
                [datetime.now().isoformat(' '), 'CRITICAL', log])
            stat_iface = STAT_LVL['crit']
            print(log)

        else:
            log = 'Successfully checked GPIO interrupt flag after {0} attempts.'.\
                  format(attempt)
            logger.info(log)
            MPQ_ACT.put_nowait([datetime.now().isoformat(' '), 'DEBUG', log])

        if stat_en:
            MPQ_STAT.put_nowait(['base', ['interface', stat_iface]])

        return data_iface_out, stat_iface
예제 #7
0
    def interrupt_clear_flag(self, attempts: int = 3, stat_en: bool = True):
        """
        Clears GPIO interrupt

        :param attempts: int
        :param stat_en: bool

        :return stat_iface: STAT_LVL['op'] or STAT_LVL['crit']
        """
        attempt = 0
        err_iface = True
        stat_iface = STAT_LVL['op']

        # Cycle through attempts
        for attempt in range(1, (attempts + 1)):
            err_iface = self.obj_janus.interrupt_clear_flag()

            if err_iface:
                MPQ_STAT.put_nowait(
                    ['base', ['interface', STAT_LVL['op_err']]])

                # Only log warning on last attempt, keeps log clean
                if attempt == attempts:
                    log = 'Attempt {0} of {1} to '.format(attempt, attempts) + \
                          'clear GPIO interrupt flag failed.'
                    logger.warning(log)
                    MPQ_ACT.put_nowait(
                        [datetime.now().isoformat(' '), 'WARNING', log])

            else:
                break

        if err_iface:
            log = 'General IO failure to clear GPIO interrupt flag.'
            logger.critical(log)
            MPQ_ACT.put_nowait(
                [datetime.now().isoformat(' '), 'CRITICAL', log])
            stat_iface = STAT_LVL['crit']
            print(log)

        else:
            log = 'Successfully cleared GPIO interrupt flag after {0} attempts.'. \
                  format(attempt)
            logger.info(log)
            MPQ_ACT.put_nowait([datetime.now().isoformat(' '), 'DEBUG', log])

        if stat_en:
            MPQ_STAT.put_nowait(['base', ['interface', stat_iface]])

        return stat_iface
예제 #8
0
def store():
    """
    Stores core time in file

    :return stat_time: STAT_LVL['op'] or STAT_LVL['op_err']
    :return stat_cdb: STAT_LVL['op'] or STAT_LVL['crit']
    """
    stat_time = STAT_LVL['op']

    # Update time document in CouchDB config database
    data_cdb_out, stat_cdb, code_cdb = dbase.cdb_request(
        cdb_cmd='upd_doc',
        cdb_name='config',
        cdb_doc='time',
        data_cdb_in={'time': str(time.time())},
        logfile=logfile
    )

    if stat_cdb:
        log = 'Could not save time due to CouchDB document update error.'
        logger.warning(log)
        MPQ_ACT.put_nowait([
            datetime.now().isoformat(' '),
            'WARNING',
            log
        ])
        MPQ_STAT.put_nowait([
            'base',
            [
                'couchdb',
                STAT_LVL['op_err']
            ]
        ])

    log = 'Time storage complete.'
    logger.info(log)
    MPQ_ACT.put_nowait([
        datetime.now().isoformat(' '),
        'INFO',
        log
    ])

    if not stat_time:
        MPQ_STAT.put_nowait([
            'base',
            [
                'tasks',
                stat_time
            ]
        ])
예제 #9
0
def update(interval: int):
    """
    Produces timed status reports

    :param interval: int
    """
    log = 'Conducting {0}-hour system status check.'.format(interval)
    logger.info(log)
    MPQ_ACT.put_nowait([datetime.now().isoformat(' '), 'INFO', log])

    # Only issue messaging if recent network check shows it is up
    send_mail(
        msg_type='status_dispatch',
        args=[],
    )

    log = '{0}-hour status check completed.'.format(interval)
    logger.info(log)
    MPQ_ACT.put_nowait([datetime.now().isoformat(' '), 'INFO', log])
    MPQ_STAT.put_nowait(['base', ['tasks', STAT_LVL['op']]])
예제 #10
0
    def snmp_notify_start(self):
        """
        Starts SNMP notify

        self.args[0] = host ip
        self.args[1] = host port
        self.args[1] = host community
        """
        from server.snmp import notification

        # SNMP notifier must be placed in thread rather than
        # multiprocess process because dynamic variables are shared
        # between main process and the agent
        obj_snmpn = notification.SNMPNotify(
            self.args[0],
            self.args[1],
            self.args[2]
        )
        try:
            th_snmpn = threading.Thread(
                target=obj_snmpn.listener,
                args=()
            )
            th_snmpn.start()
            MPQ_STAT.put_nowait([
                'snmp_notify',
                th_snmpn.ident
            ])

        except threading.ThreadError:
            log = 'Could not start SNMP notifier due to threading error.'
            logger.exception(log)
            MPQ_ACT.put_nowait([
                datetime.now().isoformat(' '),
                'CRITICAL',
                log
            ])
            MPQ_STAT.put_nowait([
                'snmp_notify',
                False
            ])
예제 #11
0
def clear():
    """
    Produces timed status reports
    """
    # Clear queues at most every 24 hours to prevent filling up.
    # There is no better way to clear a multiprocessing queue other than run a loop.
    log = 'Attempting to clear activity and status queues.'
    logger.debug(log)
    MPQ_ACT.put_nowait([datetime.now().isoformat(' '), 'DEBUG', log])

    while not MPQ_STAT.empty():
        MPQ_STAT.get()
        time.sleep(0.001)

    while not MPQ_ACT.empty():
        MPQ_ACT.get()
        time.sleep(0.001)

    log = 'Activity and status queues cleared.'
    logger.info(log)
    MPQ_ACT.put_nowait([datetime.now().isoformat(' '), 'INFO', log])
예제 #12
0
    def dispatcher(self):
        # Register an imaginary never-ending job to keep I/O dispatcher running forever
        self.eng_snmp.transportDispatcher.jobStarted(1)

        # Run I/O dispatcher which would receive queries and send responses
        try:
            log = 'SNMP agent dispatcher started.'
            logger.info(log)
            MPQ_ACT.put_nowait([datetime.now().isoformat(' '), 'INFO', log])
            MPQ_STAT.put_nowait(['base', ['snmp_agent', STAT_LVL['op']]])
            self.eng_snmp.transportDispatcher.runDispatcher()

        except queue.Full:
            log = 'SNMP agent dispatcher experienced critical error.'
            logger.critical(log)
            print(log)
            MPQ_ACT.put_nowait(
                [datetime.now().isoformat(' '), 'CRITICAL', log])
            MPQ_STAT.put_nowait(['base', ['snmp_agent', STAT_LVL['crit']]])
            self.eng_snmp.tr0ansportDispatcher.closeDispatcher()
            raise
예제 #13
0
def mdb_check():
    logfile = 'janusess'
    logger = logging.getLogger(logfile)

    check_time = 3.0

    log = 'Checking MariaDB every {0} sec until operational.'.format(
        check_time)
    logger.debug(log)

    count = 1

    while True:
        try:
            mdb_conn = mysql.connector.connect(
                user='******',
                password='******',
                host='127.0.0.1',
                database='aurora',
                unix_socket='/run/mysqld/mysqld.sock')
            mdb_conn.close()
            stat_mdb = STAT_LVL['op']

            log = 'MariaDB is operational.'
            logger.info(log)
            MPQ_ACT.put_nowait([datetime.now().isoformat(' '), 'INFO', log])
            MPQ_STAT.put_nowait(['base', ['mariadb', stat_mdb]])

        except mysql.connector.Error:
            stat_mdb = STAT_LVL['not_cfg']
            log = 'Local MariaDB server did not respond to check. Trying again.'
            logger.warning(log)
            MPQ_ACT.put_nowait([datetime.now().isoformat(' '), 'WARNING', log])
            MPQ_STAT.put_nowait(['base', ['mariadb', stat_mdb]])

        if stat_mdb < STAT_LVL['not_cfg']:
            break

        count += count
        time.sleep(check_time)
예제 #14
0
    def listener(
        self
    ):
        """
        Listener to open when a page websocket connection is established
        """
        try:
            self.mp_ws_listener = multiprocessing.Process(
                target=self.websocket,
                args=()
            )

            self.mp_ws_listener.start()
            pid_handler = self.mp_ws_listener.pid
            log = 'Flask websocket handler opened, pid: {0}.'.format(pid_handler)
            logger.info(log)

            MPQ_STAT.put_nowait([
                'websocket',
                self.mp_ws_listener.pid
            ])

        except multiprocessing.ProcessError:
            pid_handler = False
            log = 'Can not dispatch heartbeat channel encoded messages ' + \
                  'due to multiprocessing error.'
            logger.exception(log)

        data_cdb_out, stat_cdb, http_cdb = dbase.cdb_request(
            cdb_cmd='upd_doc',
            cdb_name='config',
            cdb_doc='base_pid',
            data_cdb_in={'websocket_handler': pid_handler},
            logfile=logfile
        )

        if stat_cdb:
            log = 'Could not update websocket PID values in process status document due to CouchDB error.'
            logger.warning(log)
예제 #15
0
def cdb_check():
    """
    Checks CouchDB if ready to accept transactions
    """
    logfile = 'janusess'
    logger = logging.getLogger(logfile)

    check_time = 0.5

    log = 'Checking CouchDB every {0} sec until operational.'.format(
        check_time)
    logger.debug(log)

    count = 1
    while True:

        # Issue CouchDB GET request and process result
        http_resp = requests.get('http://127.0.0.1:5984/')

        # Successful GET request
        if http_resp.status_code == 200:
            log = 'CouchDB is operational.'
            logger.info(log)
            MPQ_ACT.put_nowait([datetime.now().isoformat(' '), 'INFO', log])
            MPQ_STAT.put_nowait(['base', ['couchdb', STAT_LVL['op']]])
            break

        # All GET errors
        else:
            log = 'CouchDB is not operational, failed with http ' +\
                  'response {0}.  Making another attempt.'.format(http_resp.status_code)
            logger.warning(log)
            MPQ_ACT.put_nowait([datetime.now().isoformat(' '), 'WARNING', log])
            MPQ_STAT.put_nowait(['base', ['couchdb', STAT_LVL['cfg_err']]])

        count += count
        time.sleep(check_time)
예제 #16
0
    def listener(self):
        """
        Listens for notification activity and assigns to appropriate process
        """
        log = 'SNMP notification listener started.'
        logger.info(log)
        print(log)
        MPQ_ACT.put_nowait([datetime.now().isoformat(' '), 'INFO', log])
        MPQ_STAT.put_nowait(['base', ['snmp_notify', STAT_LVL['op']]])

        # Poll SNMP agent queues for values to update variables
        while True:
            if not MPQ_SNMPN_STOP.empty():
                MPQ_SNMPN_STOP.get()
                break

            if not MPQ_SNMPN2.empty():
                mpq_record = MPQ_SNMPN2.get()
                self.base(mpq_record=mpq_record)

            if not MPQ_SNMPN3.empty():
                mpq_record = MPQ_SNMPN3.get()
                self.lane(mpq_record=mpq_record)

            if not MPQ_SNMPN4.empty():
                mpq_record = MPQ_SNMPN4.get()
                self.module(mpq_record=mpq_record)

            if not MPQ_SNMPN5.empty():
                mpq_record = MPQ_SNMPN5.get()
                self.poll_val(mpq_record=mpq_record)

            time.sleep(0.1)

        MPQ_STAT.put_nowait(['snmp_notify', False])

        log = 'SNMP notification listener stopped.'
        logger.info(log)
        print(log)
        MPQ_ACT.put_nowait([datetime.now().isoformat(' '), 'INFO', log])
        MPQ_STAT.put_nowait(['base', ['snmp_notify', STAT_LVL['not_cfg']]])
예제 #17
0
def listener():
    """
    Listener for commands to execute
    """
    from application.polling import flag, poll

    # Initialize operations and Janus interface libraries
    # Enable interrupts immediately
    obj_cmd = Command()
    obj_iface = Interface()
    obj_iface.interrupts_enable()

    # Send message to JanusESS main to proceed with JanusESS startup procedures
    MPQ_IFACE_SETUP.put_nowait(obj_iface.error_iface())

    stat_cmd_prev = STAT_LVL['not_cfg']

    # This while loop has no exit, JanusESS will not function without this
    # ongoing loop to check the following command queues in priority order:
    #
    #   MPQ_CMD0: User-initiated command requests
    #   MPQ_CMD1: Checks for neighbor-bus triggers
    #   MPQ_CMD2: User-initiated module sensor polling
    #   MPQ_CMD3: Lane/module initialization and setup routine
    #   MPQ_CMD4: Upload module configuration to module
    #   MPQ_CMD5: Recurring module sensor polling
    while True:
        stat_cmd = STAT_LVL['op']

        # User-initiated command requests
        if not MPQ_CMD0.empty():
            data_cmd0_in = MPQ_CMD0.get()
            log = 'Priority 0 command, command #{0} request received.'.\
                  format(data_cmd0_in['command'])
            logger.debug(log)

            log = 'Command {0} called.'.format(data_cmd0_in['command'])
            logger.info(log)

            if data_cmd0_in['command'] == 'log_level':
                if data_cmd0_in['args'][0] == 'DEBUG':
                    logger.setLevel(logging.DEBUG)
                elif data_cmd0_in['args'][0] == 'INFO':
                    logger.setLevel(logging.INFO)
                elif data_cmd0_in['args'][0] == 'ERROR':
                    logger.setLevel(logging.ERROR)
                elif data_cmd0_in['args'][0] == 'WARNING':
                    logger.setLevel(logging.WARNING)
                elif data_cmd0_in['args'][0] == 'CRITICAL':
                    logger.setLevel(logging.CRITICAL)

            else:
                try:
                    th_cmd0 = threading.Thread(
                        target=obj_cmd.exec_cmd,
                        args=(
                            data_cmd0_in['command'],
                            data_cmd0_in['args'],
                            data_cmd0_in['data'],
                        )
                    )
                    th_cmd0.start()

                except threading.ThreadError:
                    stat_cmd = STAT_LVL['op_err']
                    log = 'Could not start user-initiated command due to threading error.'
                    logger.exception(log)
                    MPQ_ACT.put_nowait([
                        datetime.now().isoformat(' '),
                        'CRITICAL',
                        log
                    ])

            log = 'Priority 0 interface request concluded.'
            logger.info(log)

        # Checks for neighbor-bus triggers
        #
        # This command is only executed if a trigger flag is discovered during
        # recurring module sensor polling
        elif not MPQ_CMD1.empty():
            MPQ_CMD1.get()
            log = 'Priority 1 interface request received.'
            logger.debug(log)

            # Get all documents from CouchDB lanes database
            data_cdb_out, stat_cdb, http_cdb = dbase.cdb_request(
                cdb_cmd='get_all',
                cdb_name='lanes',
                logfile=logfile
            )

            if not stat_cdb:
                # Cycle through lanes, if lane and lane
                # polling are operational, then continue procedure
                # to check module triggers
                for addr_ln in range(0, 4):
                    if (data_cdb_out[addr_ln]['status'] < STAT_LVL['crit']) \
                            and (data_cdb_out[addr_ln]['poll'] <
                                 STAT_LVL['crit']):

                        # Set four-port interface lane.  This function
                        # ignores single-port interface devices.
                        stat_iface = obj_iface.i2c_lane_set(addr_ln=addr_ln)

                        if not stat_iface:
                            # Get stat_chan view from CouchDB
                            # modconfig database
                            data_cdb_out, stat_cdb, http_cdb = dbase.cdb_request(
                                cdb_cmd='get_view',
                                cdb_name='modconfig',
                                cdb_doc='stat_chan{0}'.format(addr_ln),
                                logfile=logfile,
                            )

                            # Cycle through each non-failed module connected
                            # to the lane
                            if not stat_cdb:
                                for dict_mod in data_cdb_out:
                                    if dict_mod['value']['status'] < STAT_LVL['crit']:

                                        # Call function to check an
                                        # individual module'strigger status
                                        evt_byte = MMAP[dict_mod['value']['mem_map_ver']]['M_EVT']
                                        stat_mod = flag.interrupt(
                                            obj_iface=obj_iface,
                                            addr_ln=addr_ln,
                                            addr_mod=dict_mod['key'],
                                            evt_byte=evt_byte
                                        )
                                        MPQ_STAT.put_nowait([
                                            'module', [
                                                dict_mod['id'],
                                                addr_ln,
                                                dict_mod['key'],
                                                stat_mod
                                            ]
                                        ])

                            else:
                                log = 'Could not check module interrupt flag due to CouchDB error.'
                                logger.critical(log)
                                MPQ_ACT.put_nowait([
                                    datetime.now().isoformat(' '),
                                    'CRITICAL',
                                    log
                                ])
                                stat_cmd = STAT_LVL['op_err']

                        else:
                            stat_cmd = STAT_LVL['op_err']
                            log = 'Could not complete priority 1 interface request ' + \
                                  'on lane {0} due to i2c lane '.format(addr_ln) +\
                                  'set error.'
                            logger.critical(log)
                            MPQ_ACT.put_nowait([
                                datetime.now().isoformat(' '),
                                'CRITICAL',
                                log
                            ])

                obj_iface.interrupt_clear_flag()
                log = 'Priority 1 interface request concluded.'
                logger.info(log)

            else:
                log = 'Could not complete priority 1 interface request due to CouchDB error.'
                logger.critical(log)
                MPQ_ACT.put_nowait([
                    datetime.now().isoformat(' '),
                    'CRITICAL',
                    log
                ])
                stat_cmd = STAT_LVL['op_err']

        # User-initiated module sensor polling
        #
        # This command only polls one module per request
        elif not MPQ_CMD2.empty():
            data_cmd2_in = MPQ_CMD2.get()
            uid_mod = data_cmd2_in[0]
            addr_ln = data_cmd2_in[1]
            addr_mod = data_cmd2_in[2]
            log = 'Lane {0} module {1} priority 2 interface request received.'.format(addr_ln, addr_mod)
            logger.info(log)

            # Set four-port interface lane.  This function ignores
            # single-port interface devices.
            stat_iface = obj_iface.i2c_lane_set(addr_ln=addr_ln)
            if not stat_iface:

                stat_poll_data, uid_mod_i2c = poll.get_data(
                    obj_iface=obj_iface,
                    uid_mod=uid_mod,
                    addr_ln=addr_ln,
                    addr_mod=addr_mod
                )

                if not stat_poll_data:
                    MPQ_STAT.put_nowait([
                        'base',
                        [
                            'poll_data',
                            STAT_LVL['op']
                        ]
                    ])

                    stat_iface, flag = obj_iface.interrupt_check_flag()
                    if flag:
                        MPQ_CMD1.put(True)

                    if not stat_iface:
                        log = 'Lane {0} module {1} on-demand poll completed.'.format(addr_ln, addr_mod)
                        logger.info(log)
                        MPQ_ACT.put_nowait([
                            datetime.now().isoformat(' '),
                            'INFO',
                            log
                        ])

                # USB reset interface board if bad data returned
                #
                # TODO: Need higher level tracking of this error
                # TODO: Do not wish to reset device more than once
                # TODO: If reset after first time fails, all
                # TODO:     related commands will be bypassed
                elif (stat_poll_data == STAT_LVL['op_err']) and \
                     (uid_mod_i2c != uid_mod):
                    obj_iface.setup()
                    obj_iface.interrupts_enable()

                    stat_cmd = STAT_LVL['op_err']

                    log = 'Resetting interface due to mismatch in module id: ' + \
                          'requested={0} vs polled={1}.'.format(uid_mod, uid_mod_i2c)
                    logger.warning(log)

            else:
                log = 'Could not complete priority 2 interface request on ' + \
                      'lane {0} module {1} '.format(addr_ln, addr_mod) +\
                      'due to i2c lane set error.'
                logger.critical(log)
                stat_cmd = STAT_LVL['op_err']

            log = 'Lane {0} module '.format(addr_ln) +\
                  '{0} priority 2 interface request concluded.'.format(addr_mod)
            logger.info(log)

        # Lane/module initialization and setup routine
        elif not MPQ_CMD3.empty():
            data_cmd3_in = MPQ_CMD3.get()
            addr_ln = data_cmd3_in[0]
            # FLAG_LNRST[addr_ln] = True
            log = 'Lane {0} priority 3 interface request received.'. \
                  format(addr_ln)
            logger.debug(log)

            log = 'Begin lane {0} network reset and initialization.'.\
                  format(addr_ln)
            logger.info(log)
            MPQ_ACT.put_nowait([
                datetime.now().isoformat(' '),
                'INFO',
                log
            ])

            # Call lane reset command to toggle GPIO pins
            stat_iface = lane.reset(
                obj_iface=obj_iface,
                addr_ln=addr_ln
            )

            if not stat_iface:
                # Call lane init command to setup any modules
                # connected to the lane
                stat_ch, stat_cdb = lane.init(
                    obj_iface=obj_iface,
                    addr_ln=addr_ln
                )

                if not stat_ch:
                    # Ensure that all interrupt flags are cleared prior
                    # to any other lane activity.  GPIO interrupts may
                    # get triggered during lane setup routines.
                    stat_iface = obj_iface.interrupt_clear_flag()

                    if not stat_iface:
                        log = 'Interrupt flags successfully cleared.'
                        logger.debug(log)
                        MPQ_ACT.put_nowait([
                            datetime.now().isoformat(' '),
                            'DEBUG',
                            log
                        ])

                        if not stat_cdb:
                            log = 'Lane {0} network reset and initialization complete.'.format(addr_ln)
                            logger.info(log)
                            MPQ_ACT.put_nowait([
                                datetime.now().isoformat(' '),
                                'INFO',
                                log
                            ])

                        else:
                            stat_cmd = STAT_LVL['op_err']
                            log = 'Lane {0} network reset and '.format(addr_ln) + \
                                  'initialization complete with CouchDB errors.'
                            logger.info(log)
                            MPQ_ACT.put_nowait([
                                datetime.now().isoformat(' '),
                                'WARNING',
                                log
                            ])

                    else:
                        stat_cmd = STAT_LVL['op_err']
                        log = 'Could not clear interrupt flags from interface due to interface error.'
                        logger.critical(log)
                        MPQ_ACT.put_nowait([
                            datetime.now().isoformat(' '),
                            'WARNING',
                            log
                        ])

                else:
                    stat_cmd = STAT_LVL['op_err']
                    log = 'Lane {0} network reset and initialization failed to complete.'.format(addr_ln)
                    logger.warning(log)
                    MPQ_ACT.put_nowait([
                        datetime.now().isoformat(' '),
                        'CRITICAL',
                        log
                    ])

            else:
                stat_cmd = STAT_LVL['op_err']
                log = 'Could not initialize lane {0} network due to Neighbor Bus reset error.'.format(addr_ln)
                logger.critical(log)
                MPQ_ACT.put_nowait([
                    datetime.now().isoformat(' '),
                    'CRITICAL',
                    log
                ])

            # FLAG_LNRST[addr_ln] = False
            log = 'Lane {0} priority 3 interface request concluded.'.format(addr_ln)
            logger.info(log)

        # Upload module configuration to module
        elif not MPQ_CMD4.empty():
            while not MPQ_CMD4.empty():
                data_cmd4_in = MPQ_CMD4.get()
                uid_mod = data_cmd4_in[0]
                addr_ln = data_cmd4_in[1]
                addr_mod = data_cmd4_in[2]
                addr_mem = data_cmd4_in[3]
                data_iface_in = data_cmd4_in[4]

                log = 'Lane {0} module '.format(addr_ln) +\
                      '{0} priority 4 interface request received.'.format(addr_mod)
                logger.debug(log)

                stat_mod = STAT_LVL['op']

                # Set four-port interface lane.  This function ignores
                # single-port interface devices.
                stat_iface = obj_iface.i2c_lane_set(addr_ln=addr_ln)
                if not stat_iface:

                    stat_iface = obj_iface.i2c_write(
                        addr_ln=addr_ln,
                        addr_mod=addr_mod,
                        addr_mem=addr_mem,
                        data_iface_in=data_iface_in
                    )

                    if stat_iface:
                        stat_mod = STAT_LVL['crit']
                        stat_cmd = STAT_LVL['op_err']
                        log = 'Upload of module settings to lane {0} '.format(addr_ln) +\
                              'module {0} unsuccessful.'.format(addr_mod)
                        MPQ_ACT.put_nowait([
                            datetime.now().isoformat(' '),
                            'CRITICAL',
                            log
                        ])

                    else:
                        log = 'Upload of module settings to lane {0} '.format(addr_ln) +\
                              'module {0} successful.'.format(addr_mod)
                        MPQ_ACT.put_nowait([
                            datetime.now().isoformat(' '),
                            'INFO',
                            log
                        ])

                    logger.log(
                        logging.INFO if not stat_iface else logging.CRITICAL,
                        log
                    )
                    print(log)

                    MPQ_STAT.put_nowait([
                        'module',
                        [
                            uid_mod,
                            addr_ln,
                            addr_mod,
                            stat_mod
                        ]
                    ])

                else:
                    stat_cmd = STAT_LVL['op_err']
                    log = 'Could not complete priority 4 interface request on ' + \
                          'lane {0}, '.format(addr_ln) +\
                          'module {0} due to i2c lane set error.'.format(addr_mod)
                    logger.critical(log)

                log = 'Lane {0} module '.format(addr_ln) +\
                      '{0} priority 4 interface request concluded.'.format(addr_mod)
                logger.info(log)

        # Recurring module sensor polling
        #
        # While this command algorithm is essentially identical
        # to MPQ_CMD2 algorithm, it remains separate so that any
        # user-initiated polling request upon an individual
        # module will receive a much higher priority so that
        # execution takes place more quickly.
        elif not MPQ_CMD5.empty():
            time_a = time.time()
            data_cmd5_in = MPQ_CMD5.get()
            uid_mod = data_cmd5_in[0]
            addr_ln = data_cmd5_in[1]
            addr_mod = data_cmd5_in[2]
            log = 'Lane {0} module {1} '.format(addr_ln, addr_mod) +\
                  'priority 5 interface request received.'
            logger.info(log)

            # Set four-port interface lane.  This function ignores
            # single-port interface devices.
            stat_iface = obj_iface.i2c_lane_set(addr_ln=addr_ln)

            if not stat_iface:

                time_b = time.time()
                stat_poll_data, uid_mod_i2c = poll.get_data(
                    obj_iface=obj_iface,
                    uid_mod=uid_mod,
                    addr_ln=addr_ln,
                    addr_mod=addr_mod
                )
                print('Lane {0} module {1} priority 5 get_data time: {2}'.
                      format(addr_ln, addr_mod, round((time.time() - time_b), 3)))

                # Check for any interrupts on all lanes before polling again
                if not stat_poll_data:
                    MPQ_STAT.put_nowait([
                        'base',
                        [
                            'poll_data',
                            STAT_LVL['op']
                        ]
                    ])

                    stat_iface, flag = obj_iface.interrupt_check_flag()
                    if flag:
                        MPQ_CMD1.put(True)

                # USB reset interface board if bad data returned
                #
                # TODO: Need higher level tracking of this error
                # TODO: Do not wish to reset device more than once
                # TODO: If reset after first time fails, all
                # TODO:     related commands will be bypassed
                elif (stat_poll_data == STAT_LVL['op_err']) and \
                        (uid_mod_i2c != uid_mod):
                    obj_iface.setup()
                    obj_iface.interrupts_enable()

                    stat_cmd = STAT_LVL['op_err']

                    log = 'Resetting interface due to mismatch in module id: ' + \
                          'requested={0} vs polled={1}.'.format(uid_mod, uid_mod_i2c)
                    logger.warning(log)

                MPQ_POLL_COMPLETE.put_nowait([
                    addr_ln,
                    addr_mod
                ])

            else:
                stat_cmd = STAT_LVL['op_err']
                log = 'Could not complete priority 5 interface request on lane ' + \
                      '{0} module {1} '.format(addr_ln, addr_mod) +\
                      'due to i2c lane set error.'
                logger.critical(log)

            log = 'Lane {0} module {1} '.format(addr_ln, addr_mod) +\
                  'priority 5 interface request concluded.'
            logger.info(log)
            print('Lane {0} module {1} priority 5 time: {2}'.
                  format(addr_ln, addr_mod, round((time.time() - time_a), 3)))

        time.sleep(0.05)

        # If command listener status has changed, send heartbeat update
        if stat_cmd != stat_cmd_prev:
            stat_cmd_prev = stat_cmd
            MPQ_STAT.put_nowait([
                'base',
                [
                    'command_listener',
                    stat_cmd
                ]
            ])
예제 #18
0
        'activity', 'janusess', 'command', 'conversion', 'heartbeat',
        'interface', 'polling', 'server', 'setup', 'tasks'
    ]

    for log_file in logs:
        logger = logging.getLogger(log_file)
        for i in range(1, 6):
            logger.info('')

        log = 'JanusESS logging started'
        logger.info(log)

    # Set log file for JanusESS start sequence actions
    logfile = 'janusess'
    logger = logging.getLogger(logfile)
    MPQ_STAT.put_nowait(['base', ['logging', STAT_LVL['op']]])

    # Check to determine if CouchDB is operating
    dbase.cdb_check()
    dbase.mdb_check()

    # A simple check for corrupted primary CouchDB databases
    # This check is not a guarantee that databases are corruption-free
    # If any cannot be restored, then prevent JanusESS start
    db_list = ['config', 'lanes', 'modules', 'modconfig']
    stat_cdb_dbases = dbase.recover(db_list=db_list)
    appdbase.compact()

    # Get log document from CouchDB config database
    data_cdb_out, stat_cdb, http_cdb = dbase.cdb_request(cdb_cmd='get_doc',
                                                         cdb_name='config',
예제 #19
0
    def gpio_read(self,
                  addr_ln: int,
                  mode: bool = True,
                  stat_en: bool = True,
                  attempts: int = 2):
        """
        Reads GPIO pin value

        :param addr_ln: int
        :param mode: bool
        :param stat_en: bool
        :param attempts: int

        :return data_iface_out: int (0/1 if STAT_LVL['op'])
        :return stat_iface: STAT_LVL['op'] or STAT_LVL['crit']
        """
        attempt = 0
        err_iface = True
        data_iface_out = None

        stat_iface = STAT_LVL['op']

        # Cycle through attempts
        for attempt in range(1, (attempts + 1)):

            # If mode flag is set, set GPIO mode to 'IN' prior to GPIO read
            if mode:
                err_iface = self.obj_janus.gpio_set_mode(pin=addr_ln,
                                                         mode='IN')

                if not err_iface:
                    data_iface_out, err_iface = self.obj_janus.gpio_read(
                        pin=addr_ln)

            else:
                data_iface_out, err_iface = self.obj_janus.gpio_read(
                    pin=addr_ln)

            if err_iface:
                MPQ_STAT.put_nowait(
                    ['base', ['interface', STAT_LVL['op_err']]])

                # Only log warning on last attempt, keeps log clean
                if attempt == attempts:
                    log = 'Attempt {0} of {1} to '.format(attempt, attempts) + \
                          'read GPIO pin {0} failed.'.format(addr_ln)
                    logger.warning(log)
                    MPQ_ACT.put_nowait(
                        [datetime.now().isoformat(' '), 'WARNING', log])

            else:
                break

        if err_iface:
            log = 'General IO failure to read GPIO pin {0}.'.format(addr_ln)
            logger.critical(log)
            MPQ_ACT.put_nowait(
                [datetime.now().isoformat(' '), 'CRITICAL', log])
            stat_iface = STAT_LVL['crit']
            print(log)

        else:
            log = 'Successfully read GPIO pin {0} after {1} attempts.'.\
                  format(addr_ln, attempt)
            logger.info(log)
            MPQ_ACT.put_nowait([datetime.now().isoformat(' '), 'DEBUG', log])

        if stat_en:
            MPQ_STAT.put_nowait(['base', ['interface', stat_iface]])

        return data_iface_out, stat_iface
예제 #20
0
def send_mail(
    msg_type: str,
    args: list,
):
    """
    Sends messaging message

    :param msg_type: str
    :param args: list
    """
    # Get base_status document from CouchDB config database
    data0_cdb_out, stat0_cdb, http0_cdb = dbase.cdb_request(
        cdb_cmd='get_doc',
        cdb_name='config',
        cdb_doc='base_status',
        logfile=logfile)

    # Get email document from CouchDB config database
    data1_cdb_out, stat1_cdb, http1_cdb = dbase.cdb_request(
        cdb_cmd='get_doc',
        cdb_name='config',
        cdb_doc='email',
        logfile=logfile,
    )

    # Get sms document from CouchDB config database
    data2_cdb_out, stat2_cdb, http2_cdb = dbase.cdb_request(
        cdb_cmd='get_doc',
        cdb_name='config',
        cdb_doc='sms',
        logfile=logfile,
    )

    # If messaging is enabled by user and network is operational,
    # then build template and send messaging
    if not stat0_cdb and not stat1_cdb and not stat2_cdb:

        if data1_cdb_out['smtp_enable'] and not data0_cdb_out['network']:
            dict_msg, stat_msg_temp = templates.message_templates(
                sms_enable=data2_cdb_out['sms_enable'],
                msg_type=msg_type,
                args=args)

            # Uncomment to test messaging text formatting
            # print("\n\n\n")
            # print(dict_msg['smtp_subject'])
            # print(dict_msg['smtp_body'])
            # print("\n\n\n")
            # print(dict_msg['sms_subject'])
            # print(dict_msg['sms_body'])
            # print("\n\n\n")

            # Comment this block to test message text formatting
            if not stat_msg_temp:
                try:
                    email_mp = multiprocessing.Process(target=send,
                                                       args=(data1_cdb_out,
                                                             data2_cdb_out,
                                                             dict_msg))
                    email_mp.start()

                except multiprocessing.ProcessError:
                    log = 'Can not send email due to multiprocessing error.'
                    logger.exception(log)
                    MPQ_ACT.put_nowait(
                        [datetime.now().isoformat(' '), 'ERROR', log])
                    MPQ_STAT.put_nowait(['base', ['email', STAT_LVL['crit']]])

            else:
                log = 'Email not attempted, email template build failed.'
                logger.warning(log)
                MPQ_ACT.put_nowait(
                    [datetime.now().isoformat(' '), 'WARNING', log])
                MPQ_STAT.put_nowait(['base', ['email', stat_msg_temp]])

        elif not data1_cdb_out['smtp_enable']:
            log = 'Email disabled by user.'
            logger.debug(log)
            MPQ_ACT.put_nowait([datetime.now().isoformat(' '), 'DEBUG', log])
            MPQ_STAT.put_nowait(['base', ['email', STAT_LVL['not_cfg']]])

        else:
            log = 'Email not attempted, latest network check shows network ' + \
                  'disconnected.'
            logger.info(log)
            MPQ_ACT.put_nowait([datetime.now().isoformat(' '), 'INFO', log])
            MPQ_STAT.put_nowait(['base', ['email', STAT_LVL['not_cfg']]])

    else:
        log = 'Email not attempted due to CouchDB error.'
        logger.warning(log)
        MPQ_ACT.put_nowait([datetime.now().isoformat(' '), 'WARNING', log])
        MPQ_STAT.put_nowait(['base', ['email', STAT_LVL['not_cfg']]])
예제 #21
0
def get_data(
    obj_iface: TYPE_INTERFACE,
    uid_mod: str,
    addr_ln: int,
    addr_mod: int
):
    """
    Retrieves and publishes module sensor data

    :param obj_iface: Interface Object
    :param uid_mod: str
    :param addr_ln: int
    :param addr_mod: int
    """
    # Change logging level since this operates in multiprocess
    # Cycle to last entry for most current log setting
    while not MPQ_POLL_LOG_DATA.empty():
        mpq_record = MPQ_POLL_LOG_DATA.get()
        if mpq_record[0] == 'DEBUG':
            logger.setLevel(logging.DEBUG)
        elif mpq_record[0] == 'INFO':
            logger.setLevel(logging.INFO)
        elif mpq_record[0] == 'ERROR':
            logger.setLevel(logging.ERROR)
        elif mpq_record[0] == 'WARNING':
            logger.setLevel(logging.WARNING)
        elif mpq_record[0] == 'CRITICAL':
            logger.setLevel(logging.CRITICAL)

    time_a = time.time()
    log = 'Retrieving lane {0} module {1} id {2} data.'.format(addr_ln, addr_mod, uid_mod)
    logger.info(log)

    stat_poll_data = STAT_LVL['op']
    uid_mod_i2c = ''
    uid_mod_i2c_print = ''

    # Retrieve memory map version of module with I2C address of 0x7F.
    # If module responds, proceed to module setup actions, otherwise
    # mod_last_found flag is set.
    high_mmap = len(MMAP) - 1
    addr_mem = MMAP[high_mmap]['M_CFG_ALL'][0]
    data_len = MMAP[high_mmap]['M_CFG_ALL'][1]
    data0_iface_out, stat0_iface = obj_iface.i2c_read(
        addr_ln=addr_ln,
        addr_mod=addr_mod,
        addr_mem=addr_mem,
        data_len=data_len,
        stat_en=False
    )
    print('RAW POLL DATA: {0}'.format(data0_iface_out))
    print('Lane {0} module {1} get_data i2c config time: {2}'.
          format(addr_ln, addr_mod, round((time.time() - time_a), 3)))
    if stat0_iface:
        log = 'Lane {0} module {1} poll can '.format(addr_ln, addr_mod) + \
              'not be completed due to I2C interface error.'
        logger.critical(log)
        MPQ_ACT.put_nowait([
            datetime.now().isoformat(' '),
            'CRITICAL',
            log
        ])
        print(log)
        MPQ_STAT.put_nowait([
            'base',
            [
                'poll_data',
                STAT_LVL['op_err']
            ]
        ])
        MPQ_STAT.put_nowait([
            'module',
            [
                uid_mod,
                addr_ln,
                addr_mod,
                STAT_LVL['op_err']
            ]
        ])
        stat_poll_data = STAT_LVL['op_err']

    else:
        # Build module id string from I2C data
        mod_uid_end = MMAP[data0_iface_out[2]]['M_UID'][0] + \
                      MMAP[data0_iface_out[2]]['M_UID'][1] - 1
        mod_uid_begin = MMAP[data0_iface_out[2]]['M_UID'][0] - 1
        for addr_mem in range(mod_uid_end, mod_uid_begin, -1):
            uidmod_i2c = str(hex(data0_iface_out[addr_mem]))[2:]
            if len(uidmod_i2c) == 1:
                uidmod_i2c = '0' + uidmod_i2c
            uid_mod_i2c += uidmod_i2c

        # Check that module ids match, then proceed with data collection and reporting
        uid_mod_print = ''.join(char for char in uid_mod.strip() if isprint(char))
        uid_mod_i2c_print = ''.join(char for char in uid_mod_i2c.strip() if isprint(char))
        if uid_mod_i2c_print == uid_mod_print:

            time_b = time.time()
            # Get module document from CouchDB modconfig database
            data0_cdb_out, stat0_cdb, http0_cdb = dbase.cdb_request(
                cdb_cmd='get_doc',
                cdb_name='modconfig',
                cdb_doc=uid_mod_print,
                logfile=logfile
            )

            # Get cloud document from CouchDB config database
            data1_cdb_out, stat1_cdb, http1_cdb = dbase.cdb_request(
                cdb_cmd='get_doc',
                cdb_name='config',
                cdb_doc='cloud',
                logfile=logfile
            )

            # Get core document from CouchDB config database
            data2_cdb_out, stat2_cdb, http2_cdb = dbase.cdb_request(
                cdb_cmd='get_doc',
                cdb_name='config',
                cdb_doc='core',
                logfile=logfile
            )
            print(
                'Lane {0} module {1} get_data database time: {2}'.
                format(addr_ln, addr_mod, round((time.time() - time_b), 3)))
            if not stat0_cdb and not stat1_cdb and not stat2_cdb:
                module_stat = STAT_LVL['op']

                poll_data_mod = []
                poll_head_mod = [
                    uid_mod_i2c_print,
                    data2_cdb_out['customer'],
                    data2_cdb_out['name'],
                    data0_cdb_out['loc'],
                    addr_ln,
                    addr_mod,
                ]

                # Retrieves sensor polling value from module
                time_c = time.time()
                data_iface_out, stat_iface = obj_iface.i2c_read(
                    addr_ln=addr_ln,
                    addr_mod=addr_mod,
                    addr_mem=MMAP[data0_iface_out[2]]['S_ALL_VAL'][0],
                    data_len=MMAP[data0_iface_out[2]]['S_ALL_VAL'][1]
                )
                print('Lane {0} module {1} get_data i2c sensor time: {2}'.
                      format(addr_ln, addr_mod, round((time.time() - time_c), 3)))
                print(data_iface_out)
                if not stat_iface:

                    # Cycle through all sensors installed on the module
                    led_ctl = Control()
                    for addr_s in range(0, int(data0_cdb_out['num_sensors'])):
                        sensor = 'S{0}'.format(addr_s)

                        log = 'Retrieving lane {0} module {1} sensor {2} data.'.\
                              format(addr_ln, addr_mod, addr_s)
                        logger.debug(log)

                        # Initialize polling data packet
                        data_dtg = time.time()
                        poll_data_s = [addr_s]

                        # Convert raw values to floating point number, and add to packet
                        val_raw = struct.pack(
                            'BBBB',
                            int(data_iface_out[3 + (addr_s * 4)]),
                            int(data_iface_out[2 + (addr_s * 4)]),
                            int(data_iface_out[1 + (addr_s * 4)]),
                            int(data_iface_out[0 + (addr_s * 4)])
                        )
                        val_convert = round(
                            struct.unpack('>f', val_raw)[0],
                            data0_cdb_out[sensor]['precision']
                        )

                        if (val_convert >= data0_cdb_out[sensor]['min']) or \
                                (val_convert <= data0_cdb_out[sensor]['max']):

                            trig_low = round(
                                float(data0_cdb_out[sensor]['trig_low']),
                                data0_cdb_out[sensor]['precision']
                            )
                            trig_high = round(
                                float(data0_cdb_out[sensor]['trig_high']),
                                data0_cdb_out[sensor]['precision']
                            )

                            # Determine triggers
                            if val_convert < trig_low:
                                poll_data_s.append('low')
                                poll_data_s.append(True)
                                trigger = trig_low
                                module_stat = STAT_LVL['s_evt']
                                led_ctl.effect(
                                    'sensor_low',
                                    uid_mod_print,
                                    addr_ln,
                                    addr_mod
                                )

                            elif val_convert > trig_high:
                                poll_data_s.append('high')
                                poll_data_s.append(True)
                                trigger = trig_high
                                module_stat = STAT_LVL['s_evt']
                                led_ctl.effect(
                                    'sensor_high',
                                    uid_mod_print,
                                    addr_ln,
                                    addr_mod
                                )

                            else:
                                poll_data_s.append('off')
                                poll_data_s.append(False)
                                trigger = 0.0

                            poll_data_s.append(data0_cdb_out[sensor]['type'])
                            poll_data_s.append(val_convert)
                            poll_data_s.append(data_dtg)
                            poll_data_s.append(data0_cdb_out[sensor]['unit'])
                            poll_data_s.append(trigger)
                            poll_data_s.append(data0_cdb_out[sensor]['trig_int'])
                            poll_data_s.append(data0_cdb_out[sensor]['trig_step'])

                            poll_data_mod.append(poll_data_s)
                            MPQ_STAT.put_nowait([
                                'poll',
                                [
                                    poll_head_mod,
                                    poll_data_s
                                ]
                            ])

                    time_e = time.time()
                    store_data(data1_cdb_out, poll_head_mod, poll_data_mod)
                    print('Lane {0} module {1} get_data store data time: {2}'.
                          format(addr_ln, addr_mod, round((time.time() - time_e), 3)))

                else:
                    log = 'Lane {0} module {1} '.format(addr_ln, addr_mod) + \
                          'data not added to storage queue due to I2C errors.'
                    logger.critical(log)
                    MPQ_ACT.put_nowait([
                        datetime.now().isoformat(' '),
                        'CRITICAL',
                        log
                    ])
                    stat_poll_data = STAT_LVL['op_err']
                    module_stat = STAT_LVL['op_err']

            else:
                log = 'Lane {0} module {1} '.format(addr_ln, addr_mod) + \
                      'data not added to storage queue due to CouchDB errors.'
                logger.critical(log)
                MPQ_ACT.put_nowait([
                    datetime.now().isoformat(' '),
                    'CRITICAL',
                    log
                ])
                stat_poll_data = STAT_LVL['op_err']
                module_stat = STAT_LVL['op_err']

            log = 'Completed lane {0} module {1} poll.'.format(addr_ln, addr_mod)
            logger.info(log)
            MPQ_ACT.put_nowait([
                datetime.now().isoformat(' '),
                'DEBUG',
                log
            ])
            MPQ_STAT.put_nowait([
                'base',
                [
                    'poll_data',
                    stat_poll_data
                ]
            ])

            MPQ_STAT.put_nowait([
                'module',
                [
                    uid_mod_print,
                    addr_ln,
                    addr_mod,
                    module_stat
                ]
            ])

        else:
            stat_poll_data = STAT_LVL['op_err']
            log = 'Lane {0} module {1} poll can '.format(addr_ln, addr_mod) + \
                  'not be completed due to mismatch in module id: ' + \
                  'requested={0} vs polled={1}.'.format(uid_mod_print, uid_mod_i2c_print)

            logger.critical(log)
            print(log)
            MPQ_ACT.put_nowait([
                datetime.now().isoformat(' '),
                'CRITICAL',
                log
            ])
            MPQ_STAT.put_nowait([
                'base',
                [
                    'poll_data',
                    stat_poll_data
                ]
            ])
            MPQ_STAT.put_nowait([
                'module',
                [
                    uid_mod_print,
                    addr_ln,
                    addr_mod,
                    STAT_LVL['op_err']
                ]
            ])

    return stat_poll_data, uid_mod_i2c_print
예제 #22
0
def request(file_cmd: str,
            file_name: str,
            data_loc: int,
            num_bytes: int,
            data_file_in: str,
            search_field: str = '',
            replace_line: str = '',
            logfile: str = 'janusess',
            attempts: int = 3):
    """
    Executes file transaction

    :param file_cmd: str
    :param file_name: str
    :param data_loc: int
    :param num_bytes: int
    :param search_field: str,
    :param replace_line: str,
    :param data_file_in: str
    :param logfile: str
    :param attempts: int

    :return read_err: bool
    :return data: 0 (read_err = True)
    :return data: str (read_err = False)
    """
    logger = logging.getLogger(logfile)

    stat_file = STAT_LVL['op']
    data_file_out = 0
    attempt = 1
    file_mode = ''
    field_dict = {}
    temp_path = None
    file_hdlr = None
    file_temp = None
    log_oserror = ''
    log_no_oserror = ''

    if file_cmd == 'data_read':
        file_mode = 'r'
        log_no_oserror = 'to retrieve data from file {0} succeeded.'.format(
            file_name)
        log_oserror = 'to retrieve data from file {0} failed.'.format(
            file_name)

    elif file_cmd == 'line_app':
        file_mode = 'a+'
        log_no_oserror = 'to append line to file {0} succeeded.'.format(
            file_name)
        log_oserror = 'to append line to file {0} failed.'.format(file_name)

    elif file_cmd == 'fld_read':
        file_mode = 'r'
        log_no_oserror = 'to read field from file {0} succeeded.'.format(
            file_name)
        log_oserror = 'to read field from file {0} failed.'.format(file_name)

    elif file_cmd == 'fld_read_all':
        file_mode = 'r'
        log_no_oserror = 'to read all fields from file {0} succeeded.'.format(
            file_name)
        log_oserror = 'to read all fields from file {0} failed.'.format(
            file_name)

    elif file_cmd == 'fld_edit':
        file_mode = 'r'
        log_no_oserror = 'to edit field in file {0} succeeded.'.format(
            file_name)
        log_oserror = 'to edit field in file {0} failed.'.format(file_name)

    elif file_cmd == 'data_wrt':
        file_mode = 'r+'
        log_no_oserror = 'to write data to file {0} succeeded.'.format(
            file_name)
        log_oserror = 'to write data to file {0} failed.'.format(file_name)

    elif file_cmd == 'file_replace':
        file_mode = 'w'
        log_no_oserror = 'to replace contents in file {0} succeeded.'.format(
            file_name)
        log_oserror = 'to replace contents in file {0} failed.'.format(
            file_name)

    # Cycle through attempts
    for attempt in range(1, (attempts + 1)):
        try:
            # Open file in specified mode, utf-8
            file_open = open(file_name, mode=file_mode, encoding='utf-8')

            if file_cmd == 'data_read':
                file_open.seek(data_loc)
                data_file_out = file_open.read(num_bytes)

            elif file_cmd == 'line_app':
                file_open.write(data_file_in + '\n')
                file_open.flush()

            elif file_cmd == 'fld_read':
                for line in file_open:
                    line = line.split('\n')[0]
                    key = line.split('=')[0]
                    if key == search_field:
                        data_file_out = line.split('=')[1]

            elif file_cmd == 'fld_read_all':
                for line in file_open:
                    line = line.split('\n')[0]
                    key, val = line.split('=')
                    field_dict[key] = str(val)

            elif file_cmd == 'fld_edit':
                file_hdlr, temp_path = mkstemp()
                file_temp = open(temp_path, mode='w', encoding='utf-8')

                found_field = False
                for line in file_temp:
                    if search_field in line:
                        file_temp.write(replace_line + '\n')
                        found_field = True

                    else:
                        file_temp.write(line)

                if not found_field:
                    file_temp.write(replace_line)

                file_temp.flush()

            elif file_cmd == 'data_wrt':
                file_open.seek(data_loc)
                file_open.write(data_file_in)
                file_open.flush()

            elif file_cmd == 'file_replace':
                file_open.seek(0)
                file_open.write(data_file_in)
                file_open.flush()

            # Close file
            file_open.close()

            if file_cmd == 'fld_edit':
                remove(file_name)
                move(temp_path, file_name)
                file_temp.close()
                close(file_hdlr)

            log = 'Attempt {0} of {1} '.format(attempt,
                                               (attempts - 1)) + log_no_oserror
            logger.debug(log)
            MPQ_ACT.put_nowait([datetime.now().isoformat(' '), 'DEBUG', log])
            stat_file = STAT_LVL['op']
            break

        except OSError:
            stat_file = STAT_LVL['op_err']
            MPQ_STAT.put_nowait(['base', ['file', stat_file]])
            if attempt == (attempts - 1):
                log = 'Attempt {0} of {1} '.format(
                    attempt, (attempts - 1)) + log_oserror
                logger.exception(log)
                MPQ_ACT.put_nowait(
                    [datetime.now().isoformat(' '), 'ERROR', log])

        time.sleep(0.1 * randint(0, 9) * attempt)

    log_success = ''
    log_failure = ''

    if file_cmd == 'data_read':
        log_success = 'Successfully read data from file {0} after {1} attempts.'.\
                      format(file_name, attempt)
        log_failure = 'General failure to read data from file {0}.'.format(
            file_name)

    elif file_cmd == 'line_app':
        log_success = 'Successfully appended line to file {0} after {1} attempts.'.\
                      format(file_name, attempt)
        log_failure = 'General failure to append line to file {0}.'.format(
            file_name)

    elif file_cmd == 'fld_read':
        log_success = 'Successfully read from file {0} after {1} attempts.'.\
                      format(file_name, attempt)
        log_failure = 'General failure to read field from file {0}.'.format(
            file_name)

    elif file_cmd == 'fld_read_all':
        log_success = 'Successfully read all fields from file {0} after {1} attempts.'.\
                      format(file_name, attempt)
        log_failure = 'General failure to read all fields from file {0}.'.format(
            file_name)

    elif file_cmd == 'fld_edit':
        log_success = 'Successfully edited field in file {0} after {1} attempts.'.\
                      format(file_name, attempt)
        log_failure = 'General failure to edit field in file {0}.'.format(
            file_name)

    elif file_cmd == 'data_wrt':
        log_success = 'Successfully wrote data to file {0} after {1} attempts.'.\
                      format(file_name, attempt)
        log_failure = 'General failure to write data to file {0}.'.format(
            file_name)

    elif file_cmd == 'file_replace':
        log_success = 'Successfully replaced contents in file {0} after {1} attempts.'.\
                      format(file_name, attempt)
        log_failure = 'General failure to replace contents in file {0}.'.format(
            file_name)

    if not stat_file:
        log = log_success
        activity_status = 'DEBUG'

    else:
        log = log_failure
        activity_status = 'CRITICAL'
        stat_file = STAT_LVL['crit']

    logger.log(logging.INFO if not stat_file else logging.CRITICAL, log)

    MPQ_ACT.put_nowait([datetime.now().isoformat(' '), activity_status, log])
    MPQ_STAT.put_nowait(['base', ['file', stat_file]])

    return data_file_out, stat_file
예제 #23
0
def send(
    data_cdb_smtp: dict,
    data_cdb_sms: dict,
    dict_msg: dict,
):
    """
    Sends email message

    :param data_cdb_smtp: dict
    :param data_cdb_sms: dict
    :param dict_msg: dict
    """
    stat_smtp = STAT_LVL['op']

    for attempt in range(1, 4):

        # Prepare message body, default is plain text
        smtp_email_msg = MIMEText(dict_msg['smtp_body'])
        sms_email_msg = None

        # Prepare recipients lists
        #
        # p = operational polling
        # s = system status updates
        # e = system errors
        smtp_recipients = None
        sms_recipients = None
        if dict_msg['smtp_distribution'] == 'p':
            smtp_email_msg['To'] = ', '.join(data_cdb_smtp['smtp_list_alert'])
            smtp_recipients = data_cdb_smtp['smtp_list_alert']

        elif dict_msg['smtp_distribution'] == 's':
            smtp_email_msg['To'] = ', '.join(data_cdb_smtp['smtp_list_status'])
            smtp_recipients = data_cdb_smtp['smtp_list_status']

        elif dict_msg['smtp_distribution'] == 'e':
            smtp_email_msg['To'] = ', '.join(data_cdb_smtp['smtp_list_error'])
            smtp_recipients = data_cdb_smtp['smtp_list_error']

        # Prepare message sender
        smtp_email_msg['From'] = data_cdb_smtp['smtp_from']

        # Prepare message subject line
        smtp_email_msg['Subject'] = Header(dict_msg['smtp_subject'])

        # If SMS is enabled prepare second message
        if data_cdb_sms['sms_enable']:
            sms_email_msg = MIMEText(dict_msg['sms_body'])

            sms_recipients = None
            if dict_msg['sms_distribution'] == 'p':
                sms_email_msg['To'] = ', '.join(data_cdb_sms['sms_list_alert'])
                sms_recipients = data_cdb_sms['sms_list_alert']

            elif dict_msg['sms_distribution'] == 's':
                sms_email_msg['To'] = ', '.join(
                    data_cdb_sms['sms_list_status'])
                sms_recipients = data_cdb_sms['sms_list_status']

            elif dict_msg['sms_distribution'] == 'e':
                sms_email_msg['To'] = ', '.join(data_cdb_sms['sms_list_error'])
                sms_recipients = data_cdb_sms['sms_list_error']

            sms_email_msg['From'] = data_cdb_smtp['smtp_from']
            sms_email_msg['Subject'] = Header(dict_msg['sms_subject'])

        pymail = None

        # Build SMTP server connection
        try:
            pymail = smtplib.SMTP(host=data_cdb_smtp['smtp_server'],
                                  port=data_cdb_smtp['smtp_port'],
                                  timeout=data_cdb_smtp['smtp_timeout'])

        except socket.gaierror:
            stat_smtp = STAT_LVL['crit']
            log = 'Attempt to send email failed due to unknown server.'
            logger.exception(log)
            MPQ_ACT.put_nowait([datetime.now().isoformat(' '), 'ERROR', log])

        except socket.timeout:
            stat_smtp = STAT_LVL['crit']
            log = 'Attempt to send email failed due to connection timeout.'
            logger.exception(log)
            MPQ_ACT.put_nowait([datetime.now().isoformat(' '), 'ERROR', log])

        except smtplib.SMTPConnectError:
            stat_smtp = STAT_LVL['crit']
            log = 'Attempt to connect to email server reached timeout ' +\
                  'of {0} sec.'.format(data_cdb_smtp['timeout'])
            logger.exception(log)
            MPQ_ACT.put_nowait([datetime.now().isoformat(' '), 'ERROR', log])

        except smtplib.SMTPServerDisconnected:
            stat_smtp = STAT_LVL['crit']
            log = 'Attempt to send email failed because client and ' +\
                  'server inadvertently disconnected.'
            logger.exception(log)
            MPQ_ACT.put_nowait([datetime.now().isoformat(' '), 'ERROR', log])

        except smtplib.SMTPException:
            stat_smtp = STAT_LVL['crit']
            log = 'Attempt to send email failed due to unspecified error.'
            logger.exception(log)
            MPQ_ACT.put_nowait([datetime.now().isoformat(' '), 'ERROR', log])

        if (not stat_smtp) and (data_cdb_smtp['smtp_password'] is not None):
            # Authenticate with smtp server
            try:
                pymail.login(user=data_cdb_smtp['smtp_from'],
                             password=data_cdb_smtp['smtp_password'])

            except smtplib.SMTPAuthenticationError:
                stat_smtp = STAT_LVL['crit']
                log = 'Attempt to login to email server failed due to ' +\
                      'invalid credentials.'
                logger.exception(log)
                MPQ_ACT.put_nowait(
                    [datetime.now().isoformat(' '), 'ERROR', log])

            except smtplib.SMTPException:
                stat_smtp = STAT_LVL['crit']
                log = 'Attempt to send email failed due to unspecified error.'
                logger.exception(log)
                MPQ_ACT.put_nowait(
                    [datetime.now().isoformat(' '), 'ERROR', log])

        if not stat_smtp:
            try:
                # Send message packets through SMTP server
                pymail.sendmail(from_addr=data_cdb_smtp['smtp_from'],
                                to_addrs=smtp_recipients,
                                msg=smtp_email_msg.as_string())
                if data_cdb_sms['sms_enable']:
                    if len(sms_recipients) >= 1:
                        pymail.sendmail(from_addr=data_cdb_smtp['smtp_from'],
                                        to_addrs=sms_recipients,
                                        msg=sms_email_msg.as_string())
                pymail.quit()

                log = 'Emails successfully sent.'
                logger.debug(log)
                MPQ_ACT.put_nowait(
                    [datetime.now().isoformat(' '), 'DEBUG', log])
                MPQ_STAT.put_nowait(['base', ['email', stat_smtp]])
                break

            except smtplib.SMTPException:
                stat_smtp = STAT_LVL['crit']
                log = 'Attempt to send emails failed due to unspecified error.'
                logger.debug(log)
                MPQ_ACT.put_nowait(
                    [datetime.now().isoformat(' '), 'ERROR', log])

        time.sleep(5 * attempt)

    if stat_smtp:
        log = 'General failure to send emails.'
        logger.warning(log)
        MPQ_ACT.put_nowait([datetime.now().isoformat(' '), 'WARNING', log])
        MPQ_STAT.put_nowait(['base', ['email', stat_smtp]])
예제 #24
0
    def gpio_write(self,
                   addr_ln: int,
                   data_iface_in: int,
                   mode: bool = True,
                   stat_en: bool = True,
                   attempts: int = 2):
        """
        Sets GPIO pin to output LOW signal

        :param addr_ln: int
        :param data_iface_in: int (0 or 1)
        :param mode: bool
        :param stat_en: bool
        :param attempts: int

        :return stat_iface: STAT_LVL['op'] or STAT_LVL['crit']
        """
        attempt = 0
        err_iface = True
        stat_iface = STAT_LVL['op']

        # Cycle through attempts
        for attempt in range(1, (attempts + 1)):

            # If mode flag is set, set GPIO mode to 'OUT' prior to GPIO write
            if mode:
                err_iface = self.obj_janus.gpio_set_mode(pin=addr_ln,
                                                         mode='OUT')
                if not err_iface:
                    err_iface = self.obj_janus.gpio_write(pin=addr_ln,
                                                          value=data_iface_in)
            else:
                err_iface = self.obj_janus.gpio_write(pin=addr_ln,
                                                      value=data_iface_in)

            if err_iface:
                MPQ_STAT.put_nowait(
                    ['base', ['interface', STAT_LVL['op_err']]])

                # Only log warning on last attempt, keeps log clean
                if attempt == attempts:
                    log = 'Attempt {0} of {1} to '.format(attempt, attempts) + \
                          'set GPIO pin {0} to value {1} failed.'.format(addr_ln, data_iface_in)
                    logger.warning(log)
                    MPQ_ACT.put_nowait(
                        [datetime.now().isoformat(' '), 'WARNING', log])

            else:
                break

        if err_iface:
            log = 'General IO failure to set GPIO pin {0} to value {1}.'.\
                  format(addr_ln, data_iface_in)
            logger.critical(log)
            MPQ_ACT.put_nowait(
                [datetime.now().isoformat(' '), 'CRITICAL', log])
            stat_iface = STAT_LVL['crit']
            print(log)

        else:
            log = 'Successfully set GPIO pin {0} to value {1} after {2} attempts.'.\
                  format(addr_ln, data_iface_in, attempt)
            logger.info(log)
            MPQ_ACT.put_nowait([datetime.now().isoformat(' '), 'DEBUG', log])

        if stat_en:
            MPQ_STAT.put_nowait(['base', ['interface', stat_iface]])

        return stat_iface
예제 #25
0
    def engine(self):
        """
        Setup SNMP engine and context
        """
        log = 'SNMP agent engine initialization sequence begun.  ' +\
              'This may take a minute or two.'
        logger.info(log)
        print(log)
        MPQ_ACT.put_nowait([datetime.now().isoformat(' '), 'INFO', log])

        # Create SNMP engine with auto generated engineID and pre-bound
        # to socket transport dispatcher
        self.eng_snmp = engine.SnmpEngine()

        # Transport setup

        # UDP over IPv4 at 0.0.0.0:8900
        config.addTransport(
            self.eng_snmp, udp.domainName,
            udp.UdpTransport().openServerMode(iface=('', 8900)))
        # UDP over IPv6 at [::]:8900
        config.addTransport(
            self.eng_snmp, udp6.domainName,
            udp6.Udp6Transport().openServerMode(iface=('::', 8900)))

        # SNMPv2c setup

        # SecurityName <-> CommunityName mapping.
        config.addV1System(snmpEngine=self.eng_snmp,
                           communityIndex='agent',
                           communityName='janusess')
        # Allow full MIB access for this user / securityModels at VACM
        # MIB 1.3.6.1.4.1.9934 refers to Janus Research Group
        # MIB 1.3.6.1.4.1.9934.0 refers to JanusESS Project
        config.addVacmUser(snmpEngine=self.eng_snmp,
                           securityModel=2,
                           securityName='agent',
                           securityLevel='noAuthNoPriv',
                           readSubTree=(1, 3, 6, 1, 4, 1, 9934, 0))

        # Get default SNMP context this SNMP engine serves
        self.ctx_snmp = context.SnmpContext(snmpEngine=self.eng_snmp)

        # Create custom Managed Object Instance
        self.mib_builder = self.ctx_snmp.getMibInstrum().getMibBuilder()
        mib_sources = self.mib_builder.getMibSources() + \
            (
                builder.DirMibSource('/opt/Janus/ESS/python3/server/snmp/mibs'),
            )
        self.mib_builder.setMibSources(*mib_sources)

        # JANUS-MIB defines and locates all Janus Research Group projects
        # JANUSESS-MIB defines all JanusESS project entries
        self.mib_builder.loadModules('JANUS-MIB', 'JANUSESS-MIB')

        self.config_base()
        self.config_lane()
        self.config_module()
        self.config_sensor()

        # Register SNMP Applications at the SNMP engine for particular SNMP context
        cmdrsp.GetCommandResponder(self.eng_snmp, self.ctx_snmp)
        cmdrsp.NextCommandResponder(self.eng_snmp, self.ctx_snmp)
        cmdrsp.BulkCommandResponder(self.eng_snmp, self.ctx_snmp)

        dispatcher = threading.Thread(target=self.dispatcher, args=())
        dispatcher.start()
        MPQ_STAT.put_nowait(['snmp_agent', dispatcher.ident])

        log = 'SNMP agent engine sequence concluded.'
        logger.info(log)
        MPQ_ACT.put_nowait([datetime.now().isoformat(' '), 'INFO', log])
        MPQ_STAT.put_nowait(['base', ['snmp_agent', STAT_LVL['op']]])

        log = 'SNMP agent listener started.'
        logger.info(log)
        print(log)
        MPQ_ACT.put_nowait([datetime.now().isoformat(' '), 'INFO', log])

        # Poll SNMP agent queues for values to update variables
        while True:
            if not MPQ_SNMPA_STOP.empty():
                MPQ_SNMPA_STOP.get()
                self.eng_snmp.transportDispatcher.closeDispatcher()
                break

            if not MPQ_SNMPA2.empty():
                mpq_record = MPQ_SNMPA2.get()
                self.base(mpq_record=mpq_record)

            if not MPQ_SNMPA3.empty():
                mpq_record = MPQ_SNMPA3.get()
                self.lane(mpq_record=mpq_record)

            if not MPQ_SNMPA4.empty():
                mpq_record = MPQ_SNMPA4.get()
                self.module(mpq_record=mpq_record)

            if not MPQ_SNMPA5.empty():
                mpq_record = MPQ_SNMPA5.get()
                self.sensor(mpq_record=mpq_record)

            time.sleep(0.1)

        MPQ_STAT.put_nowait(['snmp_agent', False])
        log = 'SNMP agent dispatcher stopped.'
        logger.info(log)
        MPQ_ACT.put_nowait([datetime.now().isoformat(' '), 'INFO', log])

        log = 'SNMP agent listener stopped.'
        logger.info(log)
        print(log)
        MPQ_ACT.put_nowait([datetime.now().isoformat(' '), 'INFO', log])
        MPQ_STAT.put_nowait(['base', ['snmp_agent', STAT_LVL['not_cfg']]])
예제 #26
0
def init(obj_iface: TYPE_INTERFACE, addr_ln: int):
    """
    Initializes lane

    :param obj_iface: Interface Object
    :param addr_ln: int

    :return mod_last: 0 (if STAT_LVL['crit'])
    :return mod_last: int (if STAT_LVL['op'])
    :return stat_ln: json (if STAT_LVL['op'] or STAT_LVL['not_cfg'])
    :return stat_iface: STAT_LVL['op'] or STAT_LVL['crit']
    :return stat_cdb: STAT_LVL['op'] or STAT_LVL['crit']
    """
    # Change logging level since this operates in multiprocess
    # Cycle to last entry for most current log setting
    while not MPQ_SETUP_LOG_INIT.empty():
        mpq_record = MPQ_SETUP_LOG_INIT.get()
        if mpq_record[0] == 'DEBUG':
            logger.setLevel(logging.DEBUG)
        elif mpq_record[0] == 'INFO':
            logger.setLevel(logging.INFO)
        elif mpq_record[0] == 'ERROR':
            logger.setLevel(logging.ERROR)
        elif mpq_record[0] == 'WARNING':
            logger.setLevel(logging.WARNING)
        elif mpq_record[0] == 'CRITICAL':
            logger.setLevel(logging.CRITICAL)

    stat_ln = STAT_LVL['op']
    count_mod = 0

    # Each module with an entry in CouchDB modconfig database
    # has a setup_id field that uniquely identifies the latest
    # time that it was placed on a lane and setup.
    setup_id = time.time()

    # Set lane GPIO pin to READ mode so that interrupts can
    # be captured.  This also places pin into HIGH state.
    data_iface_out, stat_iface = obj_iface.gpio_read(addr_ln=addr_ln,
                                                     mode=True,
                                                     stat_en=True)

    if not stat_iface:

        mod_last_found = False

        # Sets the lane on a four-lane interface, default
        # return of operational if interface is single lane
        stat_iface = obj_iface.i2c_lane_set(addr_ln=addr_ln)

        if not stat_iface:
            # This loop cycles through each connected module with address
            # of 0x7F until mod_last_found flag is set

            while not mod_last_found and (count_mod <= 126):

                # Retrieve memory to end of mod_uid from module with I2C address of 0x7F.
                # If module responds, proceed to module setup actions, otherwise
                # mod_last_found flag is set.
                time_a = time.time()
                high_mmap = len(MMAP) - 1
                addr_mem = MMAP[high_mmap]['M_CFG_ALL'][0]
                data_len = MMAP[high_mmap]['M_CFG_ALL'][1]

                data_iface_out, stat_iface = obj_iface.i2c_read(
                    addr_ln=addr_ln,
                    addr_mod=0x7F,
                    addr_mem=addr_mem,
                    data_len=data_len,
                    stat_en=False)

                print('lane {0} module {1} i2c_read mod_config: {2}'.format(
                    addr_ln, (count_mod + 1), round((time.time() - time_a),
                                                    3)))
                print(data_iface_out)
                # Check for proper memory map version
                if not stat_iface and (data_iface_out[2] <= high_mmap):

                    # Call module setup routine and return module id and status
                    module.setup(obj_iface=obj_iface,
                                 setup_id=setup_id,
                                 cfg_bytes=data_iface_out,
                                 addr_ln=addr_ln,
                                 addr_mod=(count_mod + 1))

                    # Increment counter before moving to another module
                    count_mod += 1

                    # Skip assigning I2C address #70 to module, on four-port interface
                    # this address used to set the lane
                    if count_mod == 70:
                        count_mod += 1

                    print('Full lane {0} module {1} setup: {2}'.format(
                        addr_ln, (count_mod - 1),
                        round((time.time() - time_a), 3)))

                # If module has improper memory map version, or if module throws error
                # on I2C read, halt lane setup routine
                #
                # Impossible to differentiate from error thrown from reading connected module
                # or error thrown by reading non-existent module, treat both as the same and
                # end lane setup routine on this module.
                else:
                    mod_last_found = True

        else:
            log = 'Could not setup lane due to interface and/or CouchDB error.'
            logger.warning(log)

        if count_mod >= 1:
            log = 'Lane {0} initialized.'.format(addr_ln)
            logger.info(log)
            print(log)
            MPQ_ACT.put_nowait([datetime.now().isoformat(' '), 'INFO', log])

            log = 'Lane {0} last module is {1}.'.format(addr_ln, count_mod)
            logger.info(log)
            print(log)
            MPQ_ACT.put_nowait([datetime.now().isoformat(' '), 'INFO', log])

        else:
            log = 'No modules found for lane {0}.'.format(addr_ln)
            logger.warning(log)
            print(log)
            MPQ_ACT.put_nowait([datetime.now().isoformat(' '), 'WARNING', log])
            stat_ln = STAT_LVL['not_cfg']

    else:
        log = 'Could not complete priority 3 interface request on ' + \
              'lane {0} due to i2c lane set error.'.format(addr_ln)
        logger.critical(log)
        stat_ln = STAT_LVL['not_cfg']

    MPQ_STAT.put_nowait([
        'lane',
        [
            addr_ln, {
                'status': stat_ln,
                'last_module': count_mod,
                'setup_id': setup_id
            }
        ]
    ])

    # Get stat_lane view from CouchDB modconfig database
    data_cdb_out, stat_cdb, http_cdb = dbase.cdb_request(
        cdb_cmd='get_view',
        cdb_name='modconfig',
        cdb_doc='stat_lane{0}'.format(addr_ln),
        logfile=logfile)

    mdb_sql = """
SELECT
    *
FROM
    aurora.lanes
WHERE
    lane={0}
""".format(addr_ln)

    data_mdb_out, stat_mdb, mdb_err = dbase.mdb_request(mdb_sql=mdb_sql,
                                                        logfile=logfile)
    print(stat_mdb)
    print(mdb_err)
    print(data_mdb_out)

    if not stat_cdb:
        # Iterate through modules in view, determine which modules were
        # previously connected to this lane but are no longer connected.
        # Set their lane and module addresses to NULL and their status
        # to unconfigured.
        for dict_mod in data_cdb_out:
            if dict_mod['value']['setup_id'] != setup_id:
                data_cdb_in = {
                    'lane_addr': None,
                    'mod_addr': None,
                    'status': STAT_LVL['not_cfg'],
                    'errno': 0
                }

                # Update module document in CouchDB modconfig database
                data_cdb_out, stat_cdb, http_cdb = dbase.cdb_request(
                    cdb_cmd='upd_doc',
                    cdb_name='modconfig',
                    cdb_doc=dict_mod['id'],
                    data_cdb_in=data_cdb_in,
                    logfile=logfile)

                if stat_cdb:
                    log = 'Could not update module configurations due to CouchDB error.'
                    logger.warning(log)

                print('UPDATED STATUS ON NON-EXISTENT MODULE: {0}'.format(
                    dict_mod['id']))

    else:
        log = 'Could not update module configurations due to CouchDB error.'
        logger.warning(log)

    return stat_ln, stat_cdb
예제 #27
0
def dispatcher():
    """
    Automatically dispatches polling commands into MPQ_CMD5 priority queue
    """
    stat_cdb = STAT_LVL['op']
    stat_cdb_prev = STAT_LVL['not_cfg']

    cfg_poll = [
        STAT_LVL['not_cfg'],
        STAT_LVL['not_cfg'],
        STAT_LVL['not_cfg'],
        STAT_LVL['not_cfg']
    ]

    while not stat_cdb:
        # Cycle through all lanes
        for addr_ln in range(0, 4):

            # Change logging level since this operates in multiprocess
            # Cycle to last entry for most current log setting
            while not MPQ_POLL_LOG_DISP.empty():
                mpq_record = MPQ_POLL_LOG_DISP.get()
                if mpq_record[0] == 'DEBUG':
                    logger.setLevel(logging.DEBUG)
                elif mpq_record[0] == 'INFO':
                    logger.setLevel(logging.INFO)
                elif mpq_record[0] == 'ERROR':
                    logger.setLevel(logging.ERROR)
                elif mpq_record[0] == 'WARNING':
                    logger.setLevel(logging.WARNING)
                elif mpq_record[0] == 'CRITICAL':
                    logger.setLevel(logging.CRITICAL)

            # Set polling status flag for this lane if start command is issued
            # on MPQ_POLL_START
            if not MPQ_POLL_START.empty():
                mpq_record = MPQ_POLL_START.get()
                cfg_poll[mpq_record[0]] = STAT_LVL['op']

                MPQ_STAT.put_nowait([
                    'lane',
                    [
                        mpq_record[0],
                        {'poll': cfg_poll[mpq_record[0]]}
                    ]
                ])

                # Send polling start messaging with timeout in seconds
                send_mail(
                    msg_type='poll_start',
                    args=[mpq_record[0]],
                )

            # If polling status flag is set, execute polling for lane
            if not cfg_poll[addr_ln]:

                # Get lane_status document from CouchDB lanes database
                data0_cdb_out, stat0_cdb, http0_cdb = dbase.cdb_request(
                    cdb_cmd='get_doc',
                    cdb_name='lanes',
                    cdb_doc='lane{0}_status'.format(addr_ln),
                    logfile=logfile
                )

                # Check that both lane status and polling have not failed
                if (not stat0_cdb) and (data0_cdb_out['status'] < STAT_LVL['crit']) and \
                        (data0_cdb_out['poll'] < STAT_LVL['crit']):

                    # Get stat_lane view from CouchDB modconfig database
                    data1_cdb_out, stat1_cdb, http1_cdb = dbase.cdb_request(
                        cdb_cmd='get_view',
                        cdb_name='modconfig',
                        cdb_doc='stat_lane{0}'.format(addr_ln),
                        logfile=logfile
                    )

                    if not stat1_cdb:

                        # Cycle through all modules connected to lane
                        # If a module has not failed, initiate polling actions
                        for dict_mod in data1_cdb_out:
                            if dict_mod['value']['status'] < STAT_LVL['crit']:

                                # Developer code to check for speed
                                print('priority 5 interface added')
                                time_m = time.time()

                                # Immediate stop polling for this lane
                                # if stop command is issued on MPQ_POLL_STOP
                                if not MPQ_POLL_STOP.empty():
                                    mpq_record = MPQ_POLL_STOP.get()
                                    cfg_poll[mpq_record] = STAT_LVL['not_cfg']

                                    log = 'Lane {0} polling exit command executed.'. \
                                          format(mpq_record)
                                    logger.info(log)
                                    MPQ_ACT.put_nowait([
                                        datetime.now().isoformat(' '),
                                        'INFO',
                                        log
                                    ])
                                    MPQ_STAT.put_nowait([
                                        'lane',
                                        [
                                            mpq_record,
                                            {'poll': cfg_poll[mpq_record]}
                                        ]
                                    ])

                                    # Send polling stop messaging with timeout in seconds
                                    send_mail(
                                        msg_type='poll_stop',
                                        args=[mpq_record],
                                    )

                                    if mpq_record == addr_ln:
                                        break

                                # Issue request to poll this module
                                MPQ_CMD5.put([
                                    dict_mod['id'],
                                    addr_ln,
                                    dict_mod['key']
                                ])

                                # Immediate stop polling for this lane
                                # if stop command is issued on MPQ_POLL_STOP.
                                # Second check ensures quicker response time.
                                if not MPQ_POLL_STOP.empty():
                                    mpq_record = MPQ_POLL_STOP.get()
                                    cfg_poll[mpq_record] = STAT_LVL['not_cfg']

                                    log = 'Lane {0} polling exit command executed.'.format(mpq_record)
                                    logger.info(log)
                                    MPQ_ACT.put_nowait([
                                        datetime.now().isoformat(' '),
                                        'INFO',
                                        log
                                    ])
                                    MPQ_STAT.put_nowait([
                                        'lane',
                                        [
                                            mpq_record,
                                            {'poll': cfg_poll[mpq_record]}
                                        ]
                                    ])

                                    # Send polling stop messaging with timeout in seconds
                                    send_mail(
                                        msg_type='poll_stop',
                                        args=[mpq_record],
                                    )

                                    if mpq_record == addr_ln:
                                        break

                                log = 'Lane {0} module {1} poll added to job queue.'. \
                                    format(addr_ln, dict_mod['key'])
                                logger.info(log)
                                MPQ_ACT.put_nowait([
                                    datetime.now().isoformat(' '),
                                    'DEBUG',
                                    log
                                ])

                                # Determine if all module sensor data processing is
                                # complete prior to proceeding.  This pause is here
                                # to prevent the poll dispatcher from getting too far
                                # ahead of module sensor data processing.
                                while True:
                                    if not MPQ_POLL_COMPLETE.empty():
                                        mpq_record = MPQ_POLL_COMPLETE.get()
                                        if (mpq_record[0] == addr_ln) and \
                                                (mpq_record[1] == dict_mod['key']):
                                            log = 'Lane {0} module {1} automated poll completed.'.\
                                                  format(addr_ln, dict_mod['key'])
                                            logger.info(log)
                                            MPQ_ACT.put_nowait([
                                                datetime.now().isoformat(' '),
                                                'INFO',
                                                log
                                            ])
                                            break
                                    time.sleep(0.02)

                                # Developer code to check for speed
                                print('Module {0} cycle complete: {1}'.
                                      format(dict_mod['key'], round((time.time() - time_m), 3)))

                                log = 'Lane {0} module {1} poll dispatch cycle complete.'. \
                                      format(addr_ln, dict_mod['key'])
                                logger.info(log)
                                MPQ_ACT.put_nowait([
                                    datetime.now().isoformat(' '),
                                    'DEBUG',
                                    log
                                ])

                    else:
                        stat_cdb = stat1_cdb

                    last_dtg = time.strftime(
                        '%Y-%m-%d %H:%M:%S',
                        time.localtime(time.time())
                    )
                    MPQ_STAT.put_nowait([
                        'lane',
                        [
                            addr_ln,
                            {'last_dtg': last_dtg}
                        ]
                    ])
                    time.sleep(15)

                else:
                    stat_cdb = stat0_cdb

            time.sleep(1)
            # Determine any changes in CouchDB status and report for both
            # CouchDB and poll dispatcher.  CouchDB is only cause for change in
            # poll_dispatcher status
            if stat_cdb != stat_cdb_prev:
                stat_cdb_prev = stat_cdb
                MPQ_STAT.put_nowait([
                    'base',
                    [
                        'couchdb',
                        stat_cdb
                    ]
                ])
                MPQ_STAT.put_nowait([
                    'base',
                    [
                        'poll_dispatch',
                        stat_cdb
                    ]
                ])

    log = 'Polling dispatcher failed due to CouchDB error.'
    logger.critical(log)
    MPQ_ACT.put_nowait([
        datetime.now().isoformat(' '),
        'CRITICAL',
        log
    ])
예제 #28
0
    def i2c_read(self,
                 addr_ln: int,
                 addr_mod: int,
                 addr_mem: int,
                 data_len: int,
                 stat_en: bool = True,
                 attempts: int = 1):
        """
        Reads block of bytes from I2C network

        :param addr_ln: int
        :param addr_mod: int
        :param addr_mem: int
        :param data_len: int
        :param stat_en: bool
        :param attempts: int

        :return data_iface_out: list (if STAT_LVL['op'])
        :return data_iface_out: 0 (if STAT_LVL['crit'])
        :return stat_iface: STAT_LVL['op'] or STAT_LVL['crit']
        """
        # Janus interfaces allow for 64 byte transfers, including 5 or 6 bytes of
        # addressing header information.  Modules use an memory map that is
        # 256 or 512 bytes in length, therefore breaking data into 32 byte blocks
        # is more convenient to track and error-check than 58- or 59-byte blocks.
        packet_length = 48
        number_packets = data_len // packet_length
        number_bytes = data_len % packet_length

        attempt = 0
        data_iface_out = []
        err_iface = False
        stat_iface = STAT_LVL['op']

        # Cycle through all whole blocks
        for packet in range(0, (number_packets + 1)):
            data_addr = ((packet * packet_length) + addr_mem)
            if packet < number_packets:
                data_length = packet_length
            else:
                data_length = number_bytes
            # Cycle through attempts
            for attempt in range(1, (attempts + 1)):

                # Module 0x7F read begins at later failure stage and uses
                # less corrective actions on failure to reduce setup time.
                if addr_mod == 127:
                    data_out, err_iface = self.obj_janus.i2c_read(
                        addr_i2c=addr_mod,
                        addr_mem=data_addr,
                        data_len=data_length,
                        reset=False)

                else:
                    data_out, err_iface = self.obj_janus.i2c_read(
                        addr_i2c=addr_mod,
                        addr_mem=data_addr,
                        data_len=data_length)

                if err_iface:

                    # Only process errors on attempts for non-0x7F I2C addresses
                    if addr_mod != 127:
                        MPQ_STAT.put_nowait(
                            ['base', ['interface', STAT_LVL['op_err']]])

                        # Only log warning on last attempt, keeps log clean
                        if attempt == attempts:
                            log = 'Attempt {0} of {1} to '.format(attempt, attempts) + \
                                  'read packet {0} from I2C '.format(packet) +\
                                  'link {0} module {1} failed.'.format(addr_ln, addr_mod)
                            logger.warning(log)
                            MPQ_ACT.put_nowait([
                                datetime.now().isoformat(' '), 'WARNING', log
                            ])
                    else:
                        break

                else:
                    # Add retrieved data to the end of the Python list variable
                    data_iface_out.extend(data_out)
                    break

            if err_iface:
                break

        if err_iface:
            data_iface_out = []

            # Only process errors on attempts for non-0x7F I2C addresses
            if addr_mod != 127:
                log = 'General IO failure to read data from lane {0} module {1}.'.\
                      format(addr_ln, addr_mod)
                logger.critical(log)
                MPQ_ACT.put_nowait(
                    [datetime.now().isoformat(' '), 'CRITICAL', log])
                print(log)
                stat_iface = STAT_LVL['crit']
            else:
                stat_iface = STAT_LVL['op_err']

        else:
            log = 'Successfully read data from lane {0} '.format(addr_ln) + \
                  'module {0} memory {1} length {2} '.format(addr_mod, addr_mem, data_len) +\
                  'after {0} attempts.'.format(attempt)
            logger.info(log)
            MPQ_ACT.put_nowait([datetime.now().isoformat(' '), 'DEBUG', log])

        if stat_en:
            MPQ_STAT.put_nowait(['base', ['interface', stat_iface]])

        return data_iface_out, stat_iface
예제 #29
0
def store_data(
    cloud: dict,
    poll_head: list,
    poll_data: list
):
    """
    Stores module poll data in CouchDB

    :param cloud: dict
    :param poll_head: list
    :param poll_data: list
    """
    loc_mod = poll_head[3]
    loc_mod = loc_mod.replace(' ', '\ ')
    loc_mod = loc_mod.replace(',\ ', '\,\ ')
    addr_ln = poll_head[4]
    addr_mod = poll_head[5]

    data_idb_in = ''
    data_idb_in_head = '{0},'.format(str(poll_head[0])) + \
        'customer={0},'.format(poll_head[1]) + \
        'base={0},'.format(poll_head[2]) + \
        'location={0},'.format(loc_mod) + \
        'lane={0},'.format(poll_head[4]) + \
        'module={0},'.format(poll_head[5])

    for poll_data_s in poll_data:
        s_type = poll_data_s[3]
        s_type = s_type.replace(' ', '\ ')
        s_type = s_type.replace(',\ ', '\,\ ')

        data_idb_in = data_idb_in + data_idb_in_head + \
            'sensor={0},'.format(poll_data_s[0]) + \
            'alert_type={0},'.format(poll_data_s[1]) + \
            'alert={0} '.format(poll_data_s[2]) + \
            '{0}={1} '.format(s_type, str(poll_data_s[4])) + \
            '{0}'.format(int(poll_data_s[5] * 1000000000)) +\
            "\n"

    # Store data packet to local InfluxDB JanusESS database
    try:
        http0_resp = requests.post(
            'http://localhost:8086/write?db=JanusESS',
            headers={'Content-type': 'application/octet-stream'},
            data=data_idb_in,
            timeout=2.0  # Set higher for portability to rPi v3
        )

        # Returns HTTP status codes
        if http0_resp.status_code == 204:
            log = 'Uploaded of lane {0} module {1} '.format(addr_ln, addr_mod) +\
                  'data to local InfluxDB server successful.'
            logger.debug(log)
            MPQ_ACT.put_nowait([
                datetime.now().isoformat(' '),
                'DEBUG',
                log
            ])
            MPQ_STAT.put_nowait([
                'base',
                [
                    'influxdb',
                    STAT_LVL['op']
                ]
            ])

        else:
            log = 'Could not upload lane {0} module {1} '.format(addr_ln, addr_mod) + \
                  'data to local InfluxDB server due to query error.'
            logger.warning(log)
            MPQ_ACT.put_nowait([
                datetime.now().isoformat(' '),
                'WARNING',
                log
            ])
            MPQ_STAT.put_nowait([
                'base',
                [
                    'influxdb',
                    STAT_LVL['op_err']
                ]
            ])

    except requests.exceptions.ConnectionError:
        log = 'Local InfluxDB server did not respond to request.'
        logger.critical(log)
        print(log)
        MPQ_ACT.put_nowait([
            datetime.now().isoformat(' '),
            'CRITICAL',
            log
        ])
        MPQ_STAT.put_nowait([
            'base',
            [
                'influxdb',
                STAT_LVL['crit']
            ]
        ])

    except requests.exceptions.ReadTimeout:
        log = 'Local InfluxDB server timed out on request.'
        logger.warning(log)
        print(log)
        MPQ_ACT.put_nowait([
            datetime.now().isoformat(' '),
            'WARNING',
            log
        ])
        MPQ_STAT.put_nowait([
            'base',
            [
                'influxdb',
                STAT_LVL['op_err']
            ]
        ])

    # If cloud storage is enabled, store data to cloud InfluxDB JanusESS database
    if cloud['enable']:

        # Store data packet to cloud InfluxDB JanusESS database
        server = 'http://' + cloud['url'] + ':8086/write?db=JanusESS'
        try:
            http1_resp = requests.post(
                server,
                headers={'Content-type': 'application/octet-stream'},
                data=data_idb_in,
                timeout=1
            )

            # Returns HTTP status codes
            if http1_resp.status_code == 204:
                log = 'Uploaded of lane {0} module {1} '.format(addr_ln, addr_mod) + \
                      'data to remote InfluxDB server {0} successful.'.format(cloud['url'])
                logger.debug(log)
                MPQ_ACT.put_nowait([
                    datetime.now().isoformat(' '),
                    'DEBUG',
                    log
                ])

            else:
                log = 'Could not upload lane {0} module {1} '.format(addr_ln, addr_mod) + \
                      'data to remote InfluxDB server due to query error.'
                logger.warning(log)
                MPQ_ACT.put_nowait([
                    datetime.now().isoformat(' '),
                    'WARNING',
                    log
                ])

        except requests.exceptions.ConnectionError:
            log = 'Remote InfluxDB server {0} did not respond to request.'.format(cloud['url'])
            logger.warning(log)
            MPQ_ACT.put_nowait([
                datetime.now().isoformat(' '),
                'WARNING',
                log
            ])

        except requests.exceptions.ReadTimeout:
            log = 'Remote InfluxDB server {0} timed out on request.'.format(cloud['url'])
            logger.warning(log)
            MPQ_ACT.put_nowait([
                datetime.now().isoformat(' '),
                'WARNING',
                log
            ])

    log = 'Completed storage of lane {0} module {1} data.'.format(addr_ln, addr_mod)
    logger.info(log)
예제 #30
0
    def i2c_write(self,
                  addr_ln: int,
                  addr_mod: int,
                  addr_mem: int,
                  data_iface_in: list,
                  stat_en: bool = True,
                  attempts: int = 1):
        """
        Writes block of bytes to I2C network

        :param addr_ln: int
        :param addr_mod: int
        :param addr_mem: int
        :param data_iface_in: list
        :param stat_en: bool
        :param attempts: int

        :return stat_iface: STAT_LVL['op'] or STAT_LVL['crit']
        """
        data_len = len(data_iface_in)
        packet_length = 24
        number_packets = data_len // packet_length

        attempt = 0
        err_iface = False
        stat_iface = STAT_LVL['op']

        # Cycle through all whole blocks
        for packet in range(0, (number_packets + 1)):

            if packet < number_packets:
                data_in = data_iface_in[(packet * packet_length):packet_length]
            else:
                data_in = data_iface_in[(packet * packet_length):]

            # Cycle through attempts
            for attempt in range(1, (attempts + 1)):

                # Module 0x7F write begins at later failure stage and uses
                # less corrective actions on failure to reduce setup time.

                if addr_mod == 127:
                    data_out, err_iface = self.obj_janus.i2c_write(
                        addr_i2c=addr_mod,
                        addr_mem=((packet * packet_length) + addr_mem),
                        data=data_in,
                        reset=False)
                else:
                    data_out, err_iface = self.obj_janus.i2c_write(
                        addr_i2c=addr_mod,
                        addr_mem=((packet * packet_length) + addr_mem),
                        data=data_in)

                if err_iface:

                    # Only process errors on attempts for non-0x7F I2C addresses
                    if addr_mod != 127:
                        MPQ_STAT.put_nowait(
                            ['base', ['interface', STAT_LVL['op_err']]])

                        # Only log warning on last attempt, keeps log clean
                        if attempt == attempts:
                            log = 'Attempt {0} of {1} to '.format(attempt, attempts) + \
                                  'write packet {0} to I2C '.format(packet) + \
                                  'link {0} module {1} failed.'.format(addr_ln, addr_mod)
                            logger.warning(log)
                            MPQ_ACT.put_nowait([
                                datetime.now().isoformat(' '), 'WARNING', log
                            ])
                    else:
                        break

                else:
                    break

            if err_iface:
                break

        if err_iface:

            # Only process errors on attempts for non-0x7F I2C addresses
            if addr_mod != 127:
                log = 'General IO failure to write data to lane {0} module {1}.'. \
                    format(addr_ln, addr_mod)
                logger.critical(log)
                MPQ_ACT.put_nowait(
                    [datetime.now().isoformat(' '), 'CRITICAL', log])
                print(log)
                stat_iface = STAT_LVL['crit']
            else:
                stat_iface = STAT_LVL['op_err']

        else:
            log = 'Successfully write data to lane {0} '.format(addr_ln) + \
                  'module {0} memory {1} length {2} '.format(addr_mod, addr_mem, data_len) + \
                  'after {0} attempts.'.format(attempt)
            logger.info(log)
            MPQ_ACT.put_nowait([datetime.now().isoformat(' '), 'DEBUG', log])

        if stat_en:
            MPQ_STAT.put_nowait(['base', ['interface', stat_iface]])

        return stat_iface