#!/usr/bin/python3
# coding: utf8
# LAVA Controls Copyright 2022 LAVA Controls - Stephen Loeckle


import argparse
import binascii
import collections
import configparser
import datetime
import inspect
import json
from lavacontrolscorelib import api, buildtm, checkmake, configbuilder, fetchcmdDE, fetchcmdLAVA, gettoken, jobs, netinfo, ping, QueryAPI, sendlog, savestate, sendemail, setmatrixroute, update_dict, UpdateApi, UpdateDatabase, version
import lavacontrolsneclib as lcnec
import lavacontrolssamsunglib as lcsam
import logging
from multiprocessing import Process, Queue, freeze_support
import netifaces
import os
import pickle
import platform
import serial
import socket
import socketserver
import sqlite3
import struct
import subprocess
import sys
from time import time, sleep
import traceback

osplatform = platform.system().lower()

if osplatform == 'linux':
    from lavacontrolscorelib import Timeout
elif osplatform == 'windows':
    import zc.lockfile
    from lavacontrolscorelib import wineventlog
    
PORT = 7142

class LogRecordStreamHandler(socketserver.StreamRequestHandler):
    def handle(self):
        while True:
            try:
                chunk = self.connection.recv(4)
                if len(chunk) < 4:
                    break
                slen = struct.unpack('>L', chunk)[0]
                chunk = self.connection.recv(slen)
                while len(chunk) < slen:
                    chunk = chunk + self.connection.recv(slen - len(chunk))
                obj = self.unPickle(chunk)
                record = logging.makeLogRecord(obj)
                self.handleLogRecord(record)
            except KeyboardInterrupt:
                break

    def unPickle(self, data):
#        sortedresults = collections.OrderedDict(sorted(pickle.loads(data).items()))
#        for key,val in sortedresults.items():
#            print("{0} = {1}".format(key,val))
        return pickle.loads(data)

    def handleLogRecord(self, record):
        # if a name is specified, we use the named logger rather than the one
        # implied by the record.
        if self.server.logname is not None:
            name = self.server.logname
        else:
            name = record.name
        logger = logging.getLogger(name)
        # N.B. EVERY record gets logged. This is because Logger.handle
        # is normally called AFTER logger-level filtering. If you want
        # to do filtering, do it at the client end to save wasting
        # cycles and network bandwidth!
        logger.handle(record)

class LogRecordSocketReceiver(socketserver.ThreadingTCPServer):
    allow_reuse_address = True
    lavacontrolsloggingport = 9042
    def __init__(self, host='localhost',
                 port=lavacontrolsloggingport,
                 handler=LogRecordStreamHandler):
        socketserver.ThreadingTCPServer.__init__(self, (host, port), handler)
        self.abort = 0
        self.timeout = 1
        self.logname = None

    def serve_until_stopped(self):
        import select
        abort = 0
        while not abort:
            try:
                rd, wr, ex = select.select([self.socket.fileno()],
                                           [], [],
                                           self.timeout)
                if rd:
                    self.handle_request()
                abort = self.abort
            except KeyboardInterrupt:
                break
        
def startupdisplaystatus(sysinfo, ip=None, socketid=0, q=None, id=None):
    gotthefunc = inspect.stack()[0][3]
    if osplatform == 'windows':
        logger = logging.getLogger('main')
        if sysinfo['SYSTEM']['LOGLEVEL'] == '10':
            logger.setLevel(logging.DEBUG)
        if sysinfo['SYSTEM']['LOGLEVEL'] == '20':
            logger.setLevel(logging.INFO)
        if sysinfo['SYSTEM']['LOGLEVEL'] == '30':
            logger.setLevel(logging.WARNING)
        if sysinfo['SYSTEM']['LOGLEVEL'] == '40':
            logger.setLevel(logging.ERROR)
        if sysinfo['SYSTEM']['LOGLEVEL'] == '50':
            logger.setLevel(logging.CRITICAL)

        sock = logging.handlers.SocketHandler('localhost', 9042)
        logger.addHandler(sock)
    
    msg = ('Entered {} function'.format(gotthefunc))
    sendlog(gotthefunc, msg, 10)
    ts = time()
    s = {}
    output = {}
    
    try:
        displayid, make = checkmake(sysinfo, ip, id)
    except:
        err = traceback.format_exc()
        msg = ('Error in {} Detail: {}'.format(gotthefunc,err))
        sendlog(gotthefunc, msg, 10)
        print(msg)
        sys.exit()
    
    if make == 'unknown':
        msg = 'Fatal error: Cannot determine make of display or communications to display has failed'
        sys.exit()
            
    output['D{0}'.format(displayid)] = {}
    sysinfo['D{0}'.format(displayid)] = {}
    output['D{0}'.format(displayid)]['IP'] = ip
    sysinfo['D{0}'.format(displayid)]['IP'] = ip
    output['D{0}'.format(displayid)]['ID'] = displayid
    
    if make == 'nec':
        dispconn = lcnec.DisplayInfo(sysinfo, displayid)
        output['D{0}'.format(displayid)]['MODEL'] = dispconn.getmodel()
        output['D{0}'.format(displayid)]['SERIAL'] = dispconn.getserialnumber()
        output['D{0}'.format(displayid)]['F1'],output['D{0}'.format(displayid)]['F2'],output['D{0}'.format(displayid)]['F3'],output['D{0}'.format(displayid)]['F4'] = dispconn.getfirmware()
        output['D{0}'.format(displayid)]['TEMP1'],output['D{0}'.format(displayid)]['TEMP2'],output['D{0}'.format(displayid)]['TEMP3'] = dispconn.gettemperature()
        inputconn = lcnec.Input(sysinfo, displayid)
        inputname, output['D{0}'.format(displayid)]['INPUT'] = inputconn.getinput()
        if sysinfo['SYSTEM']['MODE'] == 'wall':
            tmconn = lcnec.Tiling(sysinfo, displayid)
            output['D{0}'.format(displayid)]['TMMODE'] = tmconn.getmode()
            output['D{0}'.format(displayid)]['TMBC'] = tmconn.getbcmode()
            output['D{0}'.format(displayid)]['TMH'] = tmconn.gethsize()
            output['D{0}'.format(displayid)]['TMV'] = tmconn.getvsize()
            output['D{0}'.format(displayid)]['TMP'] = tmconn.getpos()
        coreconn = lcnec.CoreDisplaySettings(sysinfo,displayid)
        output['D{0}'.format(displayid)]['PWR'] = coreconn.getpower()
        volconn = lcnec.Volume(sysinfo, displayid)
        output['D{0}'.format(displayid)]['VOL'] = volconn.getvolume()
    if make == 'sam':
        dispconn = lcsam.DisplayInfo(sysinfo, displayid)
        output['D{0}'.format(displayid)]['MODEL'] = dispconn.getmodel()
        output['D{0}'.format(displayid)]['SERIAL'] = dispconn.getserialnumber()
        output['D{0}'.format(displayid)]['F1'],output['D{0}'.format(displayid)]['F2'],output['D{0}'.format(displayid)]['F3'],output['D{0}'.format(displayid)]['F4'] = dispconn.getfirmware()
        output['D{0}'.format(displayid)]['TEMP1'],output['D{0}'.format(displayid)]['TEMP2'],output['D{0}'.format(displayid)]['TEMP3'] = dispconn.gettemperature()
        inputconn = lcsam.Input(sysinfo,displayid)
        inputname, output['D{0}'.format(displayid)]['INPUT'] = inputconn.getinput()
        coreconn = lcsam.CoreDisplaySettings(sysinfo, displayid)
        output['D{0}'.format(displayid)]['PWR'] = coreconn.getpower()
        volconn = lcsam.Volume(sysinfo, displayid)
        output['D{0}'.format(displayid)]['VOL'] = volconn.getvolume()
    output['D{0}'.format(displayid)]['MAKE'] = make
    output['D{0}'.format(displayid)]['ST'] = 'Last process time: {0}'.format(time() - ts)
    output['D{0}'.format(displayid)]['status'] = 'Ok'
    msg = ('Exited {} function'.format(gotthefunc))
    sendlog(gotthefunc, msg, 10)
    if sysinfo['SYSTEM']['CONNECTION'] == 'ip':
        q.put(output)
    elif sysinfo['SYSTEM']['CONNECTION'] == 'serial':
        return(output)
    
def setdefaults(sysinfo, displayid=1, socketid=0, q=None):
    gotthefunc = inspect.stack()[0][3]
    if osplatform == 'windows':
        logger = logging.getLogger('main')
        if sysinfo['SYSTEM']['LOGLEVEL'] == '10':
            logger.setLevel(logging.DEBUG)
        if sysinfo['SYSTEM']['LOGLEVEL'] == '20':
            logger.setLevel(logging.INFO)
        if sysinfo['SYSTEM']['LOGLEVEL'] == '30':
            logger.setLevel(logging.WARNING)
        if sysinfo['SYSTEM']['LOGLEVEL'] == '40':
            logger.setLevel(logging.ERROR)
        if sysinfo['SYSTEM']['LOGLEVEL'] == '50':
            logger.setLevel(logging.CRITICAL)

        sock = logging.handlers.SocketHandler('localhost', 9042)
        logger.addHandler(sock)
    
    msg = ('Entered {} function with options {}'.format(gotthefunc, displayid))
    sendlog(gotthefunc, msg, 10)
    ts = time()
    s = {}
    output = {}
    if sysinfo['D{0}'.format(displayid)]['MAKE'] == 'nec':
        coreconn = lcnec.CoreDisplaySettings(sysinfo, displayid)
    if sysinfo['D{0}'.format(displayid)]['MAKE'] == 'sam':
        coreconn = lcsam.CoreDisplaySettings(sysinfo, displayid)
    output['D{0}'.format(displayid)] = {}
    output['D{0}'.format(displayid)]['SERIAL'] = sysinfo['D{0}'.format(displayid)]['SERIAL']
    output['D{0}'.format(displayid)]['OSD'] = coreconn.setosd(0)
    output['D{0}'.format(displayid)]['FUNCNAME'] = gotthefunc
    output['D{0}'.format(displayid)]['FUNCTIME'] = 'Last process time: {0}'.format(time() - ts)
    if sysinfo['D{0}'.format(displayid)]['MAKE'] == 'sam':
        coreconn.setenergysavinglfd(0)
        coreconn.setnetworkstandby(1)
        coreconn.setstandbycontrol(0)
    if q:
        q.put(output)
    else:
        msg = ('Exited {} function'.format(gotthefunc))
        sendlog(gotthefunc, msg, 10)
        return(output)
    msg = ('Exited {} function'.format(gotthefunc))
    sendlog(gotthefunc, msg, 10)

def buildtmworker(sysinfo, tileid, displayid, hnum, vnum, pos, port, socketid, q):
    gotthefunc = inspect.stack()[0][3]
    if osplatform == 'windows':
        logger = logging.getLogger('main')
        if sysinfo['SYSTEM']['LOGLEVEL'] == '10':
            logger.setLevel(logging.DEBUG)
        if sysinfo['SYSTEM']['LOGLEVEL'] == '20':
            logger.setLevel(logging.INFO)
        if sysinfo['SYSTEM']['LOGLEVEL'] == '30':
            logger.setLevel(logging.WARNING)
        if sysinfo['SYSTEM']['LOGLEVEL'] == '40':
            logger.setLevel(logging.ERROR)
        if sysinfo['SYSTEM']['LOGLEVEL'] == '50':
            logger.setLevel(logging.CRITICAL)

        sock = logging.handlers.SocketHandler('localhost', 9042)
        logger.addHandler(sock)
    
    msg = ('Entered {} function with options {} {} {} {} {}'.format(gotthefunc,displayid, hnum, vnum, pos, port))
    sendlog(gotthefunc, msg, 10)

    ts = time()
    output = {} 
    output['D{0}'.format(displayid)] = {}
    target = sysinfo['SYSTEM']['TARGET']
    s = {}
    returninput = lcnec.Input(sysinfo, displayid)
#    returnbcmode, returnhnum, returnvnum, returnpos = buildtm(target,displayid,hnum,vnum,pos,sysinfo['WALL']['NUMBERING'],s[socketid])
    if displayid != sysinfo['SYSTEM']['TARGET']:
        if sysinfo['SYSTEM']['CHAIN']['ON'] == 1:
            if sysinfo['D{0}'.format(displayid)]['TMMODE'] == 0:
               inputname, output['D{0}'.format(displayid)]['LASTINPUT'] = returninput.getinput()
            if port == 'dp':
                cmdsuccess = 0
                cmdloop = 0
                while cmdsuccess == 0 and cmdloop <= 5:
                    try:
                        inputname, output['D{0}'.format(displayid)]['INPUT'] = returninput.setinput(15)
                    except:
                        pass
                        err = traceback.format_exc()
                        msg = ('Error in {0} Detail: {1}'.format(gotthefunc,err))
                        sendlog(gotthefunc, msg, 10)
                        sleep(0.5)
                        cmdloop += 1
                    else:
                        cmdsuccess = 1
                        if cmdloop > 5:
                            msg = '{}: Reached maxiumum cmdloop in {} dp setinput'.format(displayid,gotthefunc)
                            sendlog(gotthefunc,msg, 10)
            elif port == 'hdmi':
                cmdsuccess = 0
                cmdloop = 0
                while cmdsuccess == 0 and cmdloop <= 5:
                    try:
                        inputname, output['D{0}'.format(displayid)]['INPUT'] = returninput.setinput(17)
                    except:
                        pass
                        err = traceback.format_exc()
                        msg = ('Error in {0} Detail: {1}'.format(gotthefunc,err))
                        sendlog(gotthefunc, msg, 10)
                        sleep(0.5)
                        cmdloop += 1
                    else:
                        cmdsuccess = 1
                        if cmdloop > 5:
                            msg = '{}: Reached maxiumum cmdloop in {} hdmi setinput'.format(displayid,gotthefunc)
                            sendlog(gotthefunc,msg, 10)
            msg = output['D{0}'.format(displayid)]['INPUT']
            sendlog(gotthefunc, msg, 10)
            if 'lava' in sysinfo['SYSTEM']['PLATFORM'].lower() or sysinfo['SYSTEM']['PLATFORM'].lower() == 'onprem' or sysinfo['SYSTEM']['PLATFORM'].lower() == 'on-prem':
                apidata = {}
                apidata['id'] = displayid
                apidata['lava_id'] = sysinfo['D{0}'.format(displayid)]['lava_id']
                apidata['input'] = inputname
                au = UpdateApi(sysinfo)
                au.displayUpdate(apidata)
        else:
            msg = 'D{0}: DP Chain Disabled'.format(displayid)
            sendlog(gotthefunc, msg, 10)
    else:
        msg = ('displayid from builttmworker = {}'.format(displayid))
        sendlog(gotthefunc, msg, 10)
    cmdsuccess = 0
    cmdloop = 0
    while cmdsuccess == 0 and cmdloop <= 5:
        try:
            returnbcmode, returnhnum, returnvnum, returnpos = buildtm(sysinfo, target,displayid,hnum,vnum,pos,sysinfo['WALL']['NUMBERING'],sysinfo['WALL']['LAYOUT'])
        except:
            pass
            err = traceback.format_exc()
            msg = ('Error in {0} Detail: {1}'.format(gotthefunc,err))
            sendlog(gotthefunc, msg, 10)
            sleep(0.5)
            cmdloop += 1
        else:
            cmdsuccess = 1
            if cmdloop > 5:
                msg = '{}: Reached maxiumum cmdloop in {} buildtm'.format(displayid,gotthefunc)
                sendlog(gotthefunc,msg, 10)
    sleep(0.75)
    tmconn = lcnec.Tiling(sysinfo,displayid)
    cmdsuccess = 0
    cmdloop = 0
    while cmdsuccess == 0 and cmdloop <= 5:
        try:
            returntmmode = tmconn.setmode(1)
        except:
            pass
            err = traceback.format_exc()
            msg = ('Error in {0} Detail: {1}'.format(gotthefunc,err))
            sendlog(gotthefunc, msg, 10)
            sleep(0.5)
            cmdloop += 1
        else:
            cmdsuccess = 1
            if cmdloop > 5:
                msg = '{}: Reached maxiumum cmdloop in {} setmode'.format(displayid,gotthefunc)
                sendlog(gotthefunc,msg, 10)
    output['D{0}'.format(displayid)]['SAVED']=0
    coreconn = lcnec.CoreDisplaySettings(sysinfo,displayid)
    cmdsuccess = 0
    cmdloop = 0
    while cmdsuccess == 0 and cmdloop <= 5:
        try:
            returnsaved = coreconn.saveconfig(2)
        except:
            pass
            err = traceback.format_exc()
            msg = ('Error in {0} Detail: {1}'.format(gotthefunc,err))
            sendlog(gotthefunc, msg, 10)
            sleep(0.5)
            cmdloop += 1
        else:
            cmdsuccess = 1
            if cmdloop > 5:
                msg = '{}: Reached maxiumum cmdloop in {} saveconfig'.format(displayid,gotthefunc)
                sendlog(gotthefunc,msg, 10)

    output['D{0}'.format(displayid)]['TMMODE']=returntmmode
    output['D{0}'.format(displayid)]['TMBC']=returnbcmode
    output['D{0}'.format(displayid)]['TMH']=returnhnum
    output['D{0}'.format(displayid)]['TMV']=returnvnum
    output['D{0}'.format(displayid)]['TMP']=returnpos
    output['D{0}'.format(displayid)]['SAVED']=returnsaved
    output['D{0}'.format(displayid)]['TILED']=1
    output['D{0}'.format(displayid)]['TMTIME'] = 'Last process time: {0}'.format(time() - ts)
    q.put(output)
    db1success = 0
    while db1success == 0:
        try:
            conn = {}
            c = {}
            conn[socketid] = sqlite3.connect(sysinfo['SYSTEM']['DATABASEFILE'])
            c[socketid] = conn[socketid].cursor()
            c[socketid].execute('INSERT into tiles (tileid, member, size, pos) values (?, ?, ?, ?)', (tileid, displayid, str(hnum)+'x'+str(vnum), pos))
            # c[socketid].execute('UPDATE displays SET input = ?, lastinput = ? WHERE lava_id = ?', (output['D{0}'.format(displayid)]['INPUT'],output['D{0}'.format(displayid)]['LASTINPUT'],sysinfo['D{0}'.format(displayid)]['lava_id']))
        except sqlite3.OperationalError:
            pass
            msg = ('{}: Database locked (8). Trying again.',format(gotthefunc))
            sendlog(gotthefunc, msg, 10)
            sleep(0.5)
        except:
            pass
            err = traceback.format_exc()
            msg = ('Error in {0} Detail: {1}'.format(gotthefunc,err))
            sendlog(gotthefunc, msg, 10)
            sleep(0.5)
        else:
            db1success = 1
            db2success = 0
            while db2success == 0:
                try:
                    conn[socketid].commit()
                except sqlite3.OperationalError:
                    pass
                    msg = ('{}: Database locked (10). Trying again.',format(gotthefunc))
                    sendlog(gotthefunc, msg, 10)
                    sleep(0.5)
                except:
                    pass
                    err = traceback.format_exc()
                    msg = ('Error in {0} Detail: {1}'.format(gotthefunc,err))
                    sendlog(gotthefunc, msg, 10)
                    sleep(0.5)
                else:
                    db2success = 1
                    conn[socketid].close()
                    
    msg = ('Exited {} function'.format(gotthefunc))
    sendlog(gotthefunc, msg, 10)

def buildtmfactory(sysinfo,h,w,tileid,displaylist=None):
    gotthefunc = inspect.stack()[0][3]
    msg = ('Entered {} function'.format(gotthefunc))
    sendlog(gotthefunc, msg, 10)
    tsmain = time()
    socketnum = 0
    targetdisplay = sysinfo['SYSTEM']['TARGET']
    targetinput = sysinfo['D{0}'.format(targetdisplay)]['INPUT']
    targetmodel = sysinfo['D{0}'.format(targetdisplay)]['MODEL'].lower()
    position = 1
    buildtmq = Queue()
    buildtmqresults = {}
    buildtmprocs = []
    necmodelswithhdmichain = ['un492', 'un552']
    if any(x in targetmodel for x in necmodelswithhdmichain) and targetinput in (3, 17):
        port = 'hdmi'
    elif any(x in targetmodel for x in necmodelswithhdmichain) and targetinput == 15:
        port = 'dp'
    else:
        port = 'dp'
    msg = 'Target display {} is of model {} with source input {} and will be using {} chain.'.format(targetdisplay, targetmodel, targetinput, port)
    sendlog(gotthefunc, msg, 10)
    msg = ('DisplayList: ',displaylist)
    sendlog(gotthefunc, msg, 10)
    if displaylist:
        for displayid in displaylist:
            buildtmproc = Process(target=buildtmworker, args=(sysinfo, tileid, displayid, h, w, position, port, socketnum, buildtmq))
            buildtmprocs.append(buildtmproc)
            socketnum += 1
            position += 1
    else:
        displayid = sysinfo['SYSTEM']['TARGET']
        msg = 'TARGET: {} H: {} V: {}'.format(displayid,h,w)
        sendlog(gotthefunc, msg, 10)
        end = displayid + (h*w)
        msg = 'END: {}'.format(end)
        sendlog(gotthefunc, msg, 10)
        while (displayid < end):
            buildtmproc = Process(target=buildtmworker, args=(sysinfo, tileid, displayid, h, w, position, port, socketnum, buildtmq))
            buildtmprocs.append(buildtmproc)
            msg = 'SOCKETID: {} DISPLAYID: {} POSITION: {}'.format(socketnum,displayid,position)
            sendlog(gotthefunc, msg, 10)
            socketnum += 1
            displayid += 1
            position += 1
    if sysinfo['SYSTEM']['USEMATRIX'] == 1:
        buildtmproc = Process(target=setmatrixroute, args=(sysinfo['SYSTEM']['MATRIXIP'],sysinfo['SYSTEM']['MYIP'],sysinfo['SYSTEM']['MATRIXCOMMANDS']))
        buildtmprocs.append(buildtmproc)
        socketnum += 1
    for w in buildtmprocs:
        w.start()
    for i in range(socketnum):
        update_dict(buildtmqresults, buildtmq.get())
    for w in buildtmprocs:
        w.join()
    msg = ('Took {}'.format(time() - tsmain))
    sendlog(gotthefunc, msg, 10)
    msg = buildtmqresults
    sendlog(gotthefunc, msg, 10)
    msg = ('Exited {} function'.format(gotthefunc))
    sendlog(gotthefunc, msg, 10)
    return(buildtmqresults)

def changeinput(sysinfo, newinput, displayid=999, save=1):
    gotthefunc = inspect.stack()[0][3]
    msg = ('Entered {} function with options {} {}'.format(gotthefunc, displayid, newinput))
    sendlog(gotthefunc, msg, 10)
    if displayid == 999:
        displayid = sysinfo['SYSTEM']['TARGET']
        msg = ('CHANGEINPUT: Fetching displayid from sysinfo target: {}'.format(displayid))
        sendlog(gotthefunc, msg, 10)
    else:
        msg = ('CHANGEINPUT: Fetching displayid from arguments passed to function: {}'.format(displayid))
        sendlog(gotthefunc, msg, 10)
    ts = time()
    output = {}
    output['D{0}'.format(displayid)] = {}
    output['D{0}'.format(displayid)]['SERIAL'] = sysinfo['D{0}'.format(displayid)]['SERIAL']
    output['D{0}'.format(displayid)]['LASTINPUT'] = sysinfo['D{0}'.format(displayid)]['INPUT']
    if sysinfo['D{0}'.format(displayid)]['MAKE'] == 'nec':
        inputconn = lcnec.Input(sysinfo, displayid)
    elif sysinfo['D{0}'.format(displayid)]['MAKE'] == 'sam':
        inputconn = lcsam.Input(sysinfo, displayid)
    cmdsuccess = 0
    cmdloop = 0
    while cmdsuccess == 0 and cmdloop <= 5:
        try:
            inputname, output['D{0}'.format(displayid)]['LASTINPUT'] = inputconn.getinput()
        except:
            pass
            err = traceback.format_exc()
            msg = ('Error in {0} Detail: {1}'.format(gotthefunc,err))
            sendlog(gotthefunc, msg, 10)
            sleep(0.5)
            cmdloop += 1
        else:
            cmdsuccess = 1
            if cmdloop > 5:
                msg = '{}: Reached maxiumum cmdloop in {} getinput'.format(displayid,gotthefunc)
                sendlog(gotthefunc,msg, 10)
    cmdsuccess = 0
    cmdloop = 0
    while cmdsuccess == 0 and cmdloop <= 5:
        try:
            inputname, output['D{0}'.format(displayid)]['INPUT']=inputconn.setinput(newinput)
        except:
            pass
            err = traceback.format_exc()
            msg = ('Error in {0} Detail: {1}'.format(gotthefunc,err))
            sendlog(gotthefunc, msg, 10)
            sleep(0.5)
            cmdloop += 1
        else:
            cmdsuccess = 1
            if cmdloop > 5:
                msg = '{}: Reached maxiumum cmdloop in {} {} setinput'.format(displayid,newinput,gotthefunc)
                sendlog(gotthefunc,msg, 10)
##  Need to store hdmi mode (or any other input) states
    if sysinfo['D{0}'.format(displayid)]['MAKE'] == 'nec':
        if input == 'hdmi':
            returninputsettings = lcnec.sethdmimodes(displayid, sysinfo)
    if 'lava' in sysinfo['SYSTEM']['PLATFORM'].lower() or sysinfo['SYSTEM']['PLATFORM'].lower() == 'onprem' or sysinfo['SYSTEM']['PLATFORM'].lower() == 'on-prem':
        apidata = {}
        apidata['id'] = displayid
        apidata['lava_id'] = sysinfo['D{0}'.format(displayid)]['lava_id']
        apidata['input'] = inputname
        au = UpdateApi(sysinfo)
        au.displayUpdate(apidata)
    output['D{0}'.format(displayid)]['SAVED']=0
    if save == 1:
        if sysinfo['D{0}'.format(displayid)]['MAKE'] == 'nec':
            coreconn = lcnec.CoreDisplaySettings(sysinfo,displayid)
        elif sysinfo['D{0}'.format(displayid)]['MAKE'] == 'sam':
            coreconn = lcsam.CoreDisplaySettings(sysinfo,displayid)
        cmdsuccess = 0
        cmdloop = 0
        while cmdsuccess == 0 and cmdloop <= 5:
            try:
                returnsaved = coreconn.saveconfig(1)
            except:
                pass
                err = traceback.format_exc()
                msg = ('Error in {0} Detail: {1}'.format(gotthefunc,err))
                sendlog(gotthefunc, msg, 10)
                sleep(0.5)
                cmdloop += 1
            else:
                cmdsuccess = 1
                if cmdloop > 5:
                    msg = '{}: Reached maxiumum cmdloop in {} saveconfig'.format(displayid,gotthefunc)
                    sendlog(gotthefunc,msg, 10)
                    
        output['D{0}'.format(displayid)]['SAVED']=returnsaved
    else:
        output['D{0}'.format(displayid)]['SAVED']=0
    output['D{0}'.format(displayid)]['CHANGEINPUTTIME'] = 'Last process time: {0}'.format(time() - ts)
    msg = ('D{}: Exited {} function'.format(displayid,gotthefunc))
    sendlog(gotthefunc, msg, 10)
    UpdateDatabase(sysinfo,output)
    return(output)
    
def changeinputprocess(sysinfo, ip, displayid, newinput, socketid, q):
    gotthefunc = inspect.stack()[0][3]
    if osplatform == 'windows':
        logger = logging.getLogger('main')
        if sysinfo['SYSTEM']['LOGLEVEL'] == '10':
            logger.setLevel(logging.DEBUG)
        if sysinfo['SYSTEM']['LOGLEVEL'] == '20':
            logger.setLevel(logging.INFO)
        if sysinfo['SYSTEM']['LOGLEVEL'] == '30':
            logger.setLevel(logging.WARNING)
        if sysinfo['SYSTEM']['LOGLEVEL'] == '40':
            logger.setLevel(logging.ERROR)
        if sysinfo['SYSTEM']['LOGLEVEL'] == '50':
            logger.setLevel(logging.CRITICAL)

        sock = logging.handlers.SocketHandler('localhost', 9042)
        logger.addHandler(sock)
    
    msg = ('Entered {} function with options {} {}'.format(gotthefunc, displayid, newinput))
    sendlog(gotthefunc, msg, 10)
    ts = time()
    output = {}
    output['D{0}'.format(displayid)] = {}
    output['D{0}'.format(displayid)]['SERIAL'] = sysinfo['D{0}'.format(displayid)]['SERIAL']
    if sysinfo['D{0}'.format(displayid)]['MAKE'] == 'nec':
        inputconn = lcnec.Input(sysinfo, displayid)
    elif sysinfo['D{0}'.format(displayid)]['MAKE'] == 'sam':
        inputconn = lcsam.Input(sysinfo, displayid)
    
    inputname, output['D{0}'.format(displayid)]['LASTINPUT'] = inputconn.getinput()
    inputname, output['D{0}'.format(displayid)]['INPUT']=inputconn.setinput(newinput)
    if sysinfo['D{0}'.format(displayid)]['MAKE'] == 'nec':
        if inputname == 'hdmi' or output['D{0}'.format(displayid)]['INPUT'] == 17:
            returninputsettings = lcnec.sethdmimodes(displayid, sysinfo)
    if 'lava' in sysinfo['SYSTEM']['PLATFORM'].lower() or sysinfo['SYSTEM']['PLATFORM'].lower() == 'onprem' or sysinfo['SYSTEM']['PLATFORM'].lower() == 'on-prem':
        apidata = {}
        apidata['id'] = displayid
        apidata['lava_id'] = sysinfo['D{0}'.format(displayid)]['lava_id']
        apidata['input'] = inputname
        au = UpdateApi(sysinfo)
        au.displayUpdate(apidata)
    
    output['D{0}'.format(displayid)]['SAVED']=0
    if sysinfo['D{0}'.format(displayid)]['MAKE'] == 'nec':
        coreconn = lcnec.CoreDisplaySettings(sysinfo,displayid)
    elif sysinfo['D{0}'.format(displayid)]['MAKE'] == 'sam':
        coreconn = lcsam.CoreDisplaySettings(sysinfo,displayid)
    returnsaved = coreconn.saveconfig(1)
    output['D{0}'.format(displayid)]['SAVED']=returnsaved
    
    output['D{0}'.format(displayid)]['CHANGEINPUTTIME'] = 'Last process time: {0}'.format(time() - ts)
       
    q.put(output)
    msg = ('Exited {} function'.format(gotthefunc))
    sendlog(gotthefunc, msg, 10)

def changeinputall(sysinfo, newinput):
    gotthefunc = inspect.stack()[0][3]
    msg = ('Entered {} function with options {}'.format(gotthefunc, newinput))
    sendlog(gotthefunc, msg, 10)
    tsmain = time()
    socketnum = 0
    dpchain = 0
    changeinputallqueue = Queue()
    changeinputallqueueresults = {}
    changeinputallworkers = []
    for key, value in sysinfo.items():
        if key.startswith('D') and key != 'DNone':
            """
                Disabling legacy dpchain checking through sysinfo. It's broken with all the new changes. Use changeinputall with care.
            """
#            if sysinfo['SYSTEM']['TILE'] == 4:
#                msg = 'Currently in 2x2 tile. Checking for DP chain status'
#                sendlog(gotthefunc, msg, 10)
#                if sysinfo['SYSTEM']['CHAIN']['ON'] == 1:
#                   if sysinfo['SYSTEM']['TARGET'] == 1:
#                       dplist = [2,3,4]
#                   if sysinfo['SYSTEM']['TARGET'] == 7:
#                       dplist = [8,9,10]
#                   if any(x in key for x in dplist):
#                       dpchain = 1
#                   else:
#                       dpchain = 0
#            if sysinfo['SYSTEM']['TILE'] == 9:
#                msg = 'Currently in 3x3 tile. Checking for DP chain status'
#                sendlog(gotthefunc, msg, 10)
#                if sysinfo['SYSTEM']['CHAIN']['ON'] == 1:
#                    dplist = [2,3,4,5,6,7,8,9]
#                    if any(x in key for x in dplist):
#                        dpchain = 1
#                    else:
#                        dpchain = 0
            dpchain = 0
            if dpchain == 0:
                changeinputallworker = Process(target=changeinputprocess, args=(sysinfo, sysinfo['{0}'.format(key)]['IP'], sysinfo['{0}'.format(key)]['ID'], newinput, socketnum, changeinputallqueue))
                changeinputallworkers.append(changeinputallworker)
                changeinputallworker.start()
                socketnum += 1
            if dpchain == 1:
                changeinputallworker = Process(target=changeinputprocess, args=(sysinfo, sysinfo['{0}'.format(key)]['IP'], sysinfo['{0}'.format(key)]['ID'], 'dp', socketnum, changeinputallqueue))
                changeinputallworkers.append(changeinputallworker)
                changeinputallworker.start()
                socketnum += 1
    for i in range(socketnum):
        processresults = changeinputallqueue.get()
        update_dict(changeinputallqueueresults, processresults)
    for w in changeinputallworkers:
        w.join()
    UpdateDatabase(sysinfo,changeinputallqueueresults)
    msg = ('Took {}'.format(time() - tsmain))
    sendlog(gotthefunc, msg, 10)
    msg = ('Exited {} function'.format(gotthefunc))
    sendlog(gotthefunc, msg, 10)
    return(changeinputallqueueresults) 

def changeinputrange(sysinfo, input, quantity):
    gotthefunc = inspect.stack()[0][3]
    msg = ('Entered {} function with options {} {}'.format(gotthefunc, input, quantity))
    sendlog(gotthefunc, msg, 10)
    tsmain = time()
    socketnum = 0
    dpchain = 0
    target = sysinfo['SYSTEM']['TARGET']
    displayid = sysinfo['SYSTEM']['TARGET']
    end = displayid + quantity
    changeinputrangequeue = Queue()
    changeinputrangequeueresults = {}
    changeinputrangeworkers = []
    dplist = []
    if sysinfo['SYSTEM']['TILE'] == 4:
        msg = 'Currently in 2x2 tile. Checking for DP chain status'
        sendlog(gotthefunc, msg, 10)
        if sysinfo['SYSTEM']['CHAIN']['ON'] == 1:
            if sysinfo['SYSTEM']['TARGET'] == 1:
                dplist = [2,3,4]
            if sysinfo['SYSTEM']['TARGET'] == 7:
                dplist = [8,9,10]
    if sysinfo['SYSTEM']['TILE'] == 9:
        msg = 'Currently in 3x3 tile. Checking for DP chain status'
        sendlog(gotthefunc, msg, 10)
        if sysinfo['SYSTEM']['CHAIN']['ON'] == 1:
            dplist = [2,3,4,5,6,7,8,9]
    while (displayid < end):
        if displayid in dplist:
            msg = 'D{0}: Found in dp chain list'.format(displayid)
            sendlog(gotthefunc, msg, 10)
            changeinputrangeworker = Process(target=changeinputprocess, args=(sysinfo, sysinfo['D{0}'.format(displayid)]['IP'], sysinfo['D{0}'.format(displayid)]['ID'], 'dp', socketnum, changeinputrangequeue))
            changeinputrangeworkers.append(changeinputrangeworker)
            changeinputrangeworker.start()
            socketnum += 1
            displayid += 1
        else:
            msg = 'D{0}: Not found in dp chain list'.format(displayid)
            sendlog(gotthefunc, msg, 10)
            changeinputrangeworker = Process(target=changeinputprocess, args=(sysinfo, sysinfo['D{0}'.format(displayid)]['IP'], sysinfo['D{0}'.format(displayid)]['ID'], input, socketnum, changeinputrangequeue))
            changeinputrangeworkers.append(changeinputrangeworker)
            changeinputrangeworker.start()
            socketnum += 1
            displayid += 1
    for i in range(socketnum):
        update_dict(changeinputrangequeueresults, changeinputrangequeue.get())
    for w in changeinputrangeworkers:
        w.join()
    msg = ('Took {}'.format(time() - tsmain))
    sendlog(gotthefunc, msg, 10)
    msg = ('Exited {} function'.format(gotthefunc))
    sendlog(gotthefunc, msg, 10)
    return(changeinputrangequeueresults)
 
def changepower(sysinfo, power):
    gotthefunc = inspect.stack()[0][3]
    msg = ('Entered {} function with options {}'.format(gotthefunc, power))
    sendlog(gotthefunc, msg, 10)
    tsmain = time()
    socketnum = 0
    powerqueue = Queue()
    powerworkers = []
    for key, value in sysinfo.items():
        if key.startswith('D') and key != 'DNone':
            powerworker = Process(target=changepowerworker, args=(sysinfo, sysinfo['{0}'.format(key)]['IP'], sysinfo['{0}'.format(key)]['ID'], power, socketnum, powerqueue))
            powerworkers.append(powerworker)
            powerworker.start()
            socketnum += 1
    powerresults = {}
    for i in range(socketnum):
        update_dict(powerresults, powerqueue.get())
    msg = ('Took {}'.format(time() - tsmain))
    sendlog(gotthefunc, msg, 10)
    # Merge power results into master sysinfo dictionary
    update_dict(sysinfo, powerresults)
    msg = ('Exited {} function'.format(gotthefunc))
    sendlog(gotthefunc, msg, 10)

def changepowerworker(sysinfo, ip, displayid, power, socketid, q):
    gotthefunc = inspect.stack()[0][3]
    if osplatform == 'windows':
        logger = logging.getLogger('main')
        if sysinfo['SYSTEM']['LOGLEVEL'] == '10':
            logger.setLevel(logging.DEBUG)
        if sysinfo['SYSTEM']['LOGLEVEL'] == '20':
            logger.setLevel(logging.INFO)
        if sysinfo['SYSTEM']['LOGLEVEL'] == '30':
            logger.setLevel(logging.WARNING)
        if sysinfo['SYSTEM']['LOGLEVEL'] == '40':
            logger.setLevel(logging.ERROR)
        if sysinfo['SYSTEM']['LOGLEVEL'] == '50':
            logger.setLevel(logging.CRITICAL)

        sock = logging.handlers.SocketHandler('localhost', 9042)
        logger.addHandler(sock)
    
    msg = ('Entered {} function with options {} {}'.format(gotthefunc, displayid, power))
    sendlog(gotthefunc, msg, 10)
    ts = time()
    output = {}
    output['D{0}'.format(displayid)] = {}
    if sysinfo['D{0}'.format(displayid)]['MAKE'] == 'nec':
        coreconn = lcnec.CoreDisplaySettings(sysinfo,displayid)
    elif sysinfo['D{0}'.format(displayid)]['MAKE'] == 'sam':
        coreconn = lcsam.CoreDisplaySettings(sysinfo,displayid)
    output['D{0}'.format(displayid)]['PWR'] = coreconn.setpower(power)
    if 'lava' in sysinfo['SYSTEM']['PLATFORM'].lower() or sysinfo['SYSTEM']['PLATFORM'].lower() == 'onprem' or sysinfo['SYSTEM']['PLATFORM'].lower() == 'on-prem':
        apidata = {}
        apidata['id'] = displayid
        apidata['lava_id'] = sysinfo['D{0}'.format(displayid)]['lava_id']
        apidata['powermode'] = output['D{0}'.format(displayid)]['PWR']
        au = UpdateApi(sysinfo)
        au.displayUpdate(apidata)
    
    output['D{0}'.format(displayid)]['FUNCNAME'] = gotthefunc
    output['D{0}'.format(displayid)]['FUNCTIME'] = 'Last process time: {0}'.format(time() - ts)
    q.put(output)
    msg = ('Exited {} function'.format(gotthefunc))
    sendlog(gotthefunc, msg, 10)

def changevolume(sysinfo,resetvolume=0):
    gotthefunc = inspect.stack()[0][3]
    if isinstance( sysinfo['SYSTEM']['TARGET'], int):
        if sysinfo['SYSTEM']['TARGET'] == 0 or not sysinfo['SYSTEM']['TARGET']:
            displayid = 1
        else:
            displayid = sysinfo['SYSTEM']['TARGET']
    else:
        displayid = 1
    if resetvolume == 0:
        vol = sysinfo['SYSTEM']['COMMAND'].split("_")
    else:
        vol = resetvolume
    ip = sysinfo['D{0}'.format(sysinfo['SYSTEM']['TARGET'])]['IP']
    msg = ('Entered {} function with options {} {}'.format(gotthefunc, displayid, vol[1]))
    sendlog(gotthefunc, msg, 10)
    ts = time()
    output = {}
    output['D{0}'.format(displayid)] = {}
    try:
        if osplatform == 'linux':
            with Timeout(3):
                if sysinfo['D{0}'.format(displayid)]['MAKE'] == 'nec':
                    volconn = lcnec.Volume(sysinfo, displayid)
                elif sysinfo['D{0}'.format(displayid)]['MAKE'] == 'sam':
                    volconn = lcsam.Volume(dsysinfo, displayid)
                volconn = lcnec.Volume(sysinfo, displayid)
                output['D{0}'.format(sysinfo['SYSTEM']['TARGET'])]['VOL'] = volconn.setvolume(int(vol[1]))
        else:
            if sysinfo['D{0}'.format(displayid)]['MAKE'] == 'nec':
                volconn = lcnec.Volume(sysinfo, displayid)
            elif sysinfo['D{0}'.format(displayid)]['MAKE'] == 'sam':
                volconn = lcsam.Volume(dsysinfo, displayid)
            volconn = lcnec.Volume(sysinfo, displayid)
            output['D{0}'.format(sysinfo['SYSTEM']['TARGET'])]['VOL'] = volconn.setvolume(int(vol[1]))
    except:
        pass
        msg = ('Error in {0}'.format(gotthefunc))
        sendlog(gotthefunc, msg, 40)
        err = traceback.format_exc()
        msg = ('Error in {0} Detail: {1}'.format(gotthefunc,err))
        sendlog(gotthefunc, msg, 10)
        output['D{0}'.format(sysinfo['SYSTEM']['TARGET'])]['VOL'] = sysinfo['D{0}'.format(sysinfo['SYSTEM']['TARGET'])]['VOL']
    coreconn = lcnec.CoreDisplaySettings(sysinfo,displayid)
    returnsaved = coreconn.saveconfig(1)
    msg = ('Exited {} function'.format(gotthefunc))
    sendlog(gotthefunc, msg, 10)
    return(output)
 
def disabletmworker(sysinfo, tileid, displayid, lastinput, save, socketid, q):
    gotthefunc = inspect.stack()[0][3]
    if osplatform == 'windows':
        logger = logging.getLogger('main')
        if sysinfo['SYSTEM']['LOGLEVEL'] == '10':
            logger.setLevel(logging.DEBUG)
        if sysinfo['SYSTEM']['LOGLEVEL'] == '20':
            logger.setLevel(logging.INFO)
        if sysinfo['SYSTEM']['LOGLEVEL'] == '30':
            logger.setLevel(logging.WARNING)
        if sysinfo['SYSTEM']['LOGLEVEL'] == '40':
            logger.setLevel(logging.ERROR)
        if sysinfo['SYSTEM']['LOGLEVEL'] == '50':
            logger.setLevel(logging.CRITICAL)

        sock = logging.handlers.SocketHandler('localhost', 9042)
        logger.addHandler(sock)
    
    msg = ('Entered {} function with options {} {}'.format(gotthefunc, displayid, lastinput))
    sendlog(gotthefunc, msg, 10)

    ts = time()
    ip = sysinfo['D{}'.format(displayid)]['IP']
    output = {}
    output['D{0}'.format(displayid)] = {}
    target = sysinfo['SYSTEM']['TARGET']
    if displayid != sysinfo['SYSTEM']['TARGET']:
        inputconn = lcnec.Input(sysinfo, displayid)
        cmdsuccess = 0
        cmdloop = 0
        while cmdsuccess == 0 and cmdloop <= 5:
            try:
                inputname, output['D{0}'.format(displayid)]['INPUT'] = inputconn.setinput(lastinput)
            except:
                pass
                err = traceback.format_exc()
                msg = ('Error in {0} Detail: {1}'.format(gotthefunc,err))
                sendlog(gotthefunc, msg, 10)
                sleep(0.5)
                cmdloop += 1
            else:
                cmdsuccess = 1
                if cmdloop > 5:
                    msg = '{}: Reached maxiumum cmdloop in {} setinput'.format(displayid,gotthefunc)
                    sendlog(gotthefunc,msg, 10)
        msg = output['D{0}'.format(displayid)]['INPUT']
        sendlog(gotthefunc, msg, 10)
        if 'lava' in sysinfo['SYSTEM']['PLATFORM'].lower() or sysinfo['SYSTEM']['PLATFORM'].lower() == 'onprem' or sysinfo['SYSTEM']['PLATFORM'].lower() == 'on-prem':
            apidata = {}
            apidata['id'] = displayid
            apidata['lava_id'] = sysinfo['D{0}'.format(displayid)]['lava_id']
            apidata['input'] = inputname
            au = UpdateApi(sysinfo)
            au.displayUpdate(apidata)

#    returnbcmode, returnhnum, returnvnum, returnpos = buildtm(target,displayid,1,1,1,sysinfo['WALL']['NUMBERING'],sysinfo['WALL']['LAYOUT'],s[socketid])
    
    sleep(0.75)
    tmconn = lcnec.Tiling(sysinfo,displayid)
    cmdsuccess = 0
    cmdloop = 0
    while cmdsuccess == 0 and cmdloop <= 5:
        try:    
            returntmmode = tmconn.setmode(0)
        except:
            pass
            err = traceback.format_exc()
            msg = ('Error in {0} Detail: {1}'.format(gotthefunc,err))
            sendlog(gotthefunc, msg, 10)
            sleep(0.5)
            cmdloop += 1
        else:
            cmdsuccess = 1
            if cmdloop > 5:
                msg = '{}: Reached maxiumum cmdloop in {} setmode'.format(displayid,gotthefunc)
                sendlog(gotthefunc,msg, 10)
#    returntmmode = settm(displayid, 0, s[socketid])
    output['D{0}'.format(displayid)]['SAVED'] = 0
    if save == 1:
        coreconn = lcnec.CoreDisplaySettings(sysinfo,displayid)
        cmdsuccess = 0
        cmdloop = 0
        while cmdsuccess == 0 and cmdloop <= 5:
            try:            
                returnsaved = coreconn.saveconfig(2)
            except:
                pass
                err = traceback.format_exc()
                msg = ('Error in {0} Detail: {1}'.format(gotthefunc,err))
                sendlog(gotthefunc, msg, 10)
                sleep(0.5)
                cmdloop += 1
            else:
                cmdsuccess = 1
                if cmdloop > 5:
                    msg = '{}: Reached maxiumum cmdloop in {} saveconfig'.format(displayid,gotthefunc)
                    sendlog(gotthefunc,msg, 10)
        output['D{0}'.format(displayid)]['SAVED'] = returnsaved
    else:
        msg='D{}: Skipping Save for Quick Transition.'.format(displayid)
        sendlog(gotthefunc, msg, 10)
        output['D{0}'.format(displayid)]['SAVED'] = 0
    # **** NEED gettm status here, returning bcmode, hnum, vnum, pos *****
    output['D{0}'.format(displayid)]['TMMODE'] = returntmmode
    output['D{0}'.format(displayid)]['DISABLETMTIME'] = 'Last process time: {0}'.format(time() - ts)
    q.put(output)
    db1success = 0
    while db1success == 0:
        try:
            conn = {}
            c = {}
            conn[socketid] = sqlite3.connect(sysinfo['SYSTEM']['DATABASEFILE'])
            c[socketid] = conn[socketid].cursor()
            c[socketid].execute('DELETE from tiles WHERE member=?', (displayid, ))
        except sqlite3.OperationalError:
            pass
            msg = ('{}: Database locked (11) during delete in disabletmworker. Trying again.',format(displayid))
            sendlog(gotthefunc, msg, 10)
            sleep(0.5)
        except:
            pass
            err = traceback.format_exc()
            msg = ('Error in {0} Detail: {1}'.format(gotthefunc,err))
            sendlog(gotthefunc, msg, 10)
            sleep(0.5)
        else:
            db1success = 1                        
            db2success = 0
            while db2success == 0:
                try:
                    conn[socketid].commit()
                except sqlite3.OperationalError:
                    pass
                    msg = ('{}: Database locked (12) during commit in disabletmworker. Trying again.',format(displayid))
                    sendlog(gotthefunc, msg, 10)
                    sleep(0.5)
                except:
                    pass
                    err = traceback.format_exc()
                    msg = ('Error in {0} Detail: {1}'.format(gotthefunc,err))
                    sendlog(gotthefunc, msg, 10)
                    sleep(0.5)
                else:
                    db2success = 1        
                    conn[socketid].close()
                    
    msg = ('Exited {} function'.format(gotthefunc))
    sendlog(gotthefunc, msg, 10)

def disabletmfactory(sysinfo,tileid,save=1):
    gotthefunc = inspect.stack()[0][3]
    msg = ('Entered {} function'.format(gotthefunc))
    sendlog(gotthefunc, msg, 10)
    displaylist = []
    dbsuccess = 0
    while dbsuccess == 0:
        try:
            conn = sqlite3.connect(sysinfo['SYSTEM']['DATABASEFILE'])
            c = conn.cursor()
            c.execute('select * from tiles inner join displays on displays.id = tiles.member where tileid=?', (tileid, ))
        except sqlite3.OperationalError:
            pass
            msg = ('{}: Database locked (13). Trying again.',format(gotthefunc))
            sendlog(gotthefunc, msg, 10)
            sleep(0.5)
        except:
            pass
            err = traceback.format_exc()
            msg = ('Error in {0} Detail: {1}'.format(gotthefunc,err))
            sendlog(gotthefunc, msg, 10)
            sleep(0.5)
        else:
            dbsuccess = 1      
            rows = c.fetchall()
        finally:
            conn.close()  
#    c.execute('select member from tiles where tileid=?', (tileid, ))
    
    msg = '{}: Disable tileid {} with members {}'.format(gotthefunc,tileid,repr(rows))
    sendlog(gotthefunc, msg, 10)
    for row in rows:
        displaylist.append(row)
    tsmain = time()
    socketnum = 0
    disabletmq = Queue()
    disabletmqresults = {}
    disabletmprocs = []
    for displaydata in displaylist:
        displayid = displaydata[2]
        msg = '{}: displayid: {}'.format(gotthefunc,displayid)
        sendlog(gotthefunc, msg, 10)
        lastinput = displaydata[18]
        msg = '{}: lastinput: {}'.format(gotthefunc,lastinput)
        sendlog(gotthefunc, msg, 10)
        if not lastinput or lastinput == None:
            if sysinfo['SYSTEM']['DEFAULTINPUT'].lower() == 'dvi':
                lastinput = 3
            msg = '{}: lastinput was null, None or nonexistant. Defaulting to: {}'.format(gotthefunc,lastinput)
            sendlog(gotthefunc, msg, 10)
        disabletmproc = Process(target=disabletmworker, args=(sysinfo, tileid, displayid, lastinput, save, socketnum, disabletmq))
        disabletmprocs.append(disabletmproc)
        socketnum += 1
    for w in disabletmprocs:
        w.start()
    for i in range(socketnum):
        update_dict(disabletmqresults, disabletmq.get())
    for w in disabletmprocs:
        w.join()
    msg = ('Took {}'.format(time() - tsmain))
    sendlog(gotthefunc, msg, 10)
    msg = disabletmqresults
    sendlog(gotthefunc, msg, 10)
    msg = ('Exited {} function'.format(gotthefunc))
    sendlog(gotthefunc, msg, 10)
    return(disabletmqresults)
    
def logserver(sysinfo):
    gotthefunc = inspect.stack()[0][3]
    msg = ('Entered {} function'.format(gotthefunc))
    sendlog(gotthefunc, msg, 10)
#    logging.basicConfig(format='%(asctime)s %(processName)-10s %(name)s %(levelname)-8s %(message)s',handlers=[logging.handlers.RotatingFileHandler('/var/log/lavacontrols/lavacontrols.log', mode='a', maxBytes=10*1024*1024, backupCount=0, encoding=None, delay=False)])
    try:
        logging.basicConfig(format='%(asctime)s %(processName)-10s %(name)s %(levelname)-8s %(message)s',handlers=[logging.handlers.RotatingFileHandler(sysinfo['SYSTEM']['LAVACONTROLSLOGFILE'], mode='a', maxBytes=10000*1024, backupCount=30, encoding=None, delay=False)])
    except:
        err = traceback.format_exc()
        msg = ('Error in {0} Detail: {1}'.format(gotthefunc,err))
        sendlog(gotthefunc, msg, 10)
#    logging.basicConfig(format='%(asctime)s %(processName)-10s %(name)s %(levelname)-8s %(message)s',filename='/var/log/lavacontrols/lavacontrols.log')
    try:
        tcpserver = LogRecordSocketReceiver()
    except:
        err = traceback.format_exc()
        msg = ('Error in {0} Detail: {1}'.format(gotthefunc,err))
        sendlog(gotthefunc, msg, 10)
    try:
        tcpserver.serve_until_stopped()
    except:
        err = traceback.format_exc()
        msg = ('Error in {0} Detail: {1}'.format(gotthefunc,err))
        sendlog(gotthefunc, msg, 10)
    msg = ('Exited {} function'.format(gotthefunc))
    sendlog(gotthefunc, msg, 10)
    
def hardware(sysinfo,test):
    gotthefunc = inspect.stack()[0][3]
    if osplatform == 'windows':
        logger = logging.getLogger('main')
        if sysinfo['SYSTEM']['LOGLEVEL'] == '10':
            logger.setLevel(logging.DEBUG)
        if sysinfo['SYSTEM']['LOGLEVEL'] == '20':
            logger.setLevel(logging.INFO)
        if sysinfo['SYSTEM']['LOGLEVEL'] == '30':
            logger.setLevel(logging.WARNING)
        if sysinfo['SYSTEM']['LOGLEVEL'] == '40':
            logger.setLevel(logging.ERROR)
        if sysinfo['SYSTEM']['LOGLEVEL'] == '50':
            logger.setLevel(logging.CRITICAL)

        sock = logging.handlers.SocketHandler('localhost', 9042)
        logger.addHandler(sock)
    
    msg = ('Entered {} function'.format(gotthefunc))
    sendlog(gotthefunc, msg, 10)
    csloop = 0
    au = UpdateApi(sysinfo)
    while True:
        displaylist = None
        try:
            if osplatform == 'linux':
                with Timeout(3):
                    olddict = sysinfo.copy()
            else:
                olddict = sysinfo.copy()
        except:
            pass
            msg = ('Error 1 in {0}'.format(gotthefunc))
            sendlog(gotthefunc, msg, 40)
            err = traceback.format_exc()
            msg = ('Error 1 Detail: {0}'.format(err))
            sendlog(gotthefunc, msg, 10)
        try:
            if osplatform == 'linux':
                with Timeout(3):
                    if sysinfo['SYSTEM']['PLATFORM'].lower() == 'de':
                        cmd = fetchcmdDE(sysinfo)                        
                    else:
                        cmd = fetchcmdLAVA(sysinfo)
            else:
                if sysinfo['SYSTEM']['PLATFORM'].lower() == 'de':
                    cmd = fetchcmdDE(sysinfo)                        
                else:
                    cmd = fetchcmdLAVA(sysinfo)
        except:
            pass
            msg = ('Error 2 in {0}'.format(gotthefunc))
            sendlog(gotthefunc, msg, 40)
            err = traceback.format_exc()
            msg = ('Error 2 Detail: {0}'.format(err))
            sendlog(gotthefunc, msg, 10)
        # Merge results into master sysinfo dictionary
        msg = ('Entering update_dict function'.format(gotthefunc))
        sendlog(gotthefunc, msg, 10)
        try:
            if osplatform == 'linux':
                with Timeout(3):
                    update_dict(sysinfo, cmd)
            else:
                update_dict(sysinfo, cmd)
        except:
            pass
            msg = ('Error 3 in {0}'.format(gotthefunc))
            sendlog(gotthefunc, msg, 40)
            err = traceback.format_exc()
            msg = ('Error 3 Detail: {0}'.format(err))
            sendlog(gotthefunc, msg, 10)
        msg = ('Exited update_dict function'.format(gotthefunc))
        sendlog(gotthefunc, msg, 10)
        cmdresponse = {}
        if sysinfo['SYSTEM']['COMMAND'] != 'null' or sysinfo['SYSTEM']['COMMAND'] is not None:
            if 'input' in sysinfo['SYSTEM']['COMMAND']:
                x,y = sysinfo['SYSTEM']['COMMAND'].split('_')
                if y.lower() == 'vga':
                    inputcode = 1
                elif y.lower() == 'dvi' or y.lower() == 'dvi-all':
                    inputcode = 3
                elif y.lower() == 'video1':
                    inputcode = 5
                elif y.lower() == 'video2':
                    inputcode = 6
                elif y.lower() == 's-video':
                    inputcode = 7
                elif y.lower() == 'dvd/hd1':
                    inputcode = 12
                elif y.lower() == 'option':
                    inputcode = 13
                elif y.lower() == 'dvd/hd2':
                    inputcode = 14
                elif y.lower() == 'displayport' or y.lower() == 'dp':
                    inputcode = 15
                elif y.lower() == 'displayport2':
                    inputcode = 16
                elif y.lower() == 'hdmi' or y.lower() == 'hdmi1' or y.lower == 'hdmi-all':
                    inputcode = 17
                elif y.lower() == 'hdmi2':
                    inputcode = 18
                elif y.lower() == 'displayport3':
                    inputcode = 128
                elif y.lower() == 'hdmi3':
                    inputcode = 130
                elif y.lower() == 'hdmi4':
                    inputcode = 131
                elif y.lower() == 'mp':
                    inputcode = 135
                elif y.lower() == 'computemodule':
                    inputcode = 136
#                sysinfo['SYSTEM']['CHAINPREVIOUS']['ON'] = sysinfo['SYSTEM']['CHAIN']['ON']
#                sysinfo['SYSTEM']['CHAIN']['ON'] = 1
#                if sysinfo['SYSTEM']['CHAINPREVIOUS']['ON'] == 0:
#                    try:
#                        with Timeout(10):
#                            cmdresponse = changeinputall(sysinfo, inputcode)
#                    except Timeout.Timeout as e:
#                        pass
#                        msg = ('CSLoop changeinputall {} Class Timeout'.format(y.lower()))
#                        sendlog(gotthefunc, msg, 40)
#                    except:
#                        pass
#                        msg = ('Error 4 in {0}'.format(gotthefunc))
#                        sendlog(gotthefunc, msg, 40)
#                        err = traceback.format_exc()
#                        msg = ('Error 4 Detail: {0}'.format(err))
#                        sendlog(gotthefunc, msg, 10)
#                else:
#                    try:
#                        with Timeout(10):
#                            cmdresponse = changeinput(sysinfo, inputcode)
#                    except Timeout.Timeout as e:
#                        pass
#                        msg = ('CSLoop changeinput {} Class Timeout'.format(y.lower()))
#                        sendlog(gotthefunc, msg, 40)
#                    except:
#                        pass
#                        msg = ('Error 5 in {0}'.format(gotthefunc))
#                        sendlog(gotthefunc, msg, 40)
#                        err = traceback.format_exc()
#                        msg = ('Error 5 Detail: {0}'.format(err))
#                        sendlog(gotthefunc, msg, 10)
#                update_dict(sysinfo, cmdresponse)
#                sysinfo['SYSTEM']['BASEINPUT'] = y.lower()
            if sysinfo['SYSTEM']['COMMAND'] == 'input_computemodule':
                sysinfo['SYSTEM']['CHAINPREVIOUS']['ON'] = sysinfo['SYSTEM']['CHAIN']['ON']
                sysinfo['SYSTEM']['CHAIN']['ON'] = 1
                if sysinfo['SYSTEM']['CHAINPREVIOUS']['ON'] == 0:
                    try:
                        if osplatform == 'linux':
                            with Timeout(10):
                                cmdresponse = changeinputall(sysinfo, inputcode)
                        else:
                            cmdresponse = changeinputall(sysinfo, inputcode)
                    except:
                        pass
                        msg = ('Error 4 in {0}'.format(gotthefunc))
                        sendlog(gotthefunc, msg, 40)
                        err = traceback.format_exc()
                        msg = ('Error 4 Detail: {0}'.format(err))
                        sendlog(gotthefunc, msg, 10)
                else:
                    try:
                        if osplatform == 'linux':
                            with Timeout(10):
                                cmdresponse = changeinput(sysinfo, inputcode)
                        else:
                            cmdresponse = changeinput(sysinfo, inputcode)
                    except:
                        pass
                        msg = ('Error 5 in {0}'.format(gotthefunc))
                        sendlog(gotthefunc, msg, 40)
                        err = traceback.format_exc()
                        msg = ('Error 5 Detail: {0}'.format(err))
                        sendlog(gotthefunc, msg, 10)
                update_dict(sysinfo, cmdresponse)
            if sysinfo['SYSTEM']['COMMAND'] == 'input_option':
                sysinfo['SYSTEM']['CHAINPREVIOUS']['ON'] = sysinfo['SYSTEM']['CHAIN']['ON']
                sysinfo['SYSTEM']['CHAIN']['ON'] = 1
                if sysinfo['SYSTEM']['CHAINPREVIOUS']['ON'] == 0:
                    try:
                        if osplatform == 'linux':
                            with Timeout(10):
                                cmdresponse = changeinputall(sysinfo, inputcode)
                        else:
                            cmdresponse = changeinputall(sysinfo, inputcode)
                    except:
                        pass
                        msg = ('Error 4 in {0}'.format(gotthefunc))
                        sendlog(gotthefunc, msg, 40)
                        err = traceback.format_exc()
                        msg = ('Error 4 Detail: {0}'.format(err))
                        sendlog(gotthefunc, msg, 10)
                else:
                    try:
                        if osplatform == 'linux':
                            with Timeout(10):
                                cmdresponse = changeinput(sysinfo, inputcode)
                        else:
                            cmdresponse = changeinput(sysinfo, inputcode)
                    except:
                        pass
                        msg = ('Error 5 in {0}'.format(gotthefunc))
                        sendlog(gotthefunc, msg, 40)
                        err = traceback.format_exc()
                        msg = ('Error 5 Detail: {0}'.format(err))
                        sendlog(gotthefunc, msg, 10)
                update_dict(sysinfo, cmdresponse)
                sysinfo['SYSTEM']['BASEINPUT'] = 'dvi'
                sysinfo['SYSTEM']['BASEINPUT'] = 'dvi'
            if sysinfo['SYSTEM']['COMMAND'] == 'input_dvi':
                sysinfo['SYSTEM']['CHAINPREVIOUS']['ON'] = sysinfo['SYSTEM']['CHAIN']['ON']
                sysinfo['SYSTEM']['CHAIN']['ON'] = 1
                if sysinfo['SYSTEM']['CHAINPREVIOUS']['ON'] == 0:
                    try:
                        if osplatform == 'linux':
                            with Timeout(10):
                                cmdresponse = changeinputall(sysinfo, inputcode)
                        else:
                            cmdresponse = changeinputall(sysinfo, inputcode)
                    except:
                        pass
                        msg = ('Error 4 in {0}'.format(gotthefunc))
                        sendlog(gotthefunc, msg, 40)
                        err = traceback.format_exc()
                        msg = ('Error 4 Detail: {0}'.format(err))
                        sendlog(gotthefunc, msg, 10)
                else:
                    try:
                        if osplatform == 'linux':
                            with Timeout(10):
                                cmdresponse = changeinput(sysinfo, inputcode)
                        else:
                            cmdresponse = changeinput(sysinfo, inputcode)
                    except:
                        pass
                        msg = ('Error 5 in {0}'.format(gotthefunc))
                        sendlog(gotthefunc, msg, 40)
                        err = traceback.format_exc()
                        msg = ('Error 5 Detail: {0}'.format(err))
                        sendlog(gotthefunc, msg, 10)
                update_dict(sysinfo, cmdresponse)
                sysinfo['SYSTEM']['BASEINPUT'] = 'dvi'
            if sysinfo['SYSTEM']['COMMAND'] == 'input_dvi_4':
                sysinfo['SYSTEM']['CHAINPREVIOUS']['ON'] = sysinfo['SYSTEM']['CHAIN']['ON']
                sysinfo['SYSTEM']['CHAIN']['ON'] = 1
                try:
                    if osplatform == 'linux':
                        with Timeout(10):
                            cmdresponse = changeinputrange(sysinfo, inputcode, 4)
                    else:
                        cmdresponse = changeinputrange(sysinfo, inputcode, 4)
                except:
                    pass
                    msg = ('Error 6 in {0}'.format(gotthefunc))
                    sendlog(gotthefunc, msg, 40)
                    err = traceback.format_exc()
                    msg = ('Error 6 Detail: {0}'.format(err))
                    sendlog(gotthefunc, msg, 10)
                update_dict(sysinfo, cmdresponse)
            if sysinfo['SYSTEM']['COMMAND'] == 'input_dvi-all':
                sysinfo['SYSTEM']['CHAINPREVIOUS']['ON'] = sysinfo['SYSTEM']['CHAIN']['ON']
                sysinfo['SYSTEM']['CHAIN']['ON'] = 1
                try:
                    if osplatform == 'linux':
                        with Timeout(10):
                            cmdresponse = changeinputall(sysinfo, inputcode)
                    else:
                        cmdresponse = changeinputall(sysinfo, inputcode)
                except:
                    pass
                    msg = ('Error 7 in {0}'.format(gotthefunc))
                    sendlog(gotthefunc, msg, 40)
                    err = traceback.format_exc()
                    msg = ('Error 7 Detail: {0}'.format(err))
                    sendlog(gotthefunc, msg, 10)
                update_dict(sysinfo, cmdresponse)
                sysinfo['SYSTEM']['BASEINPUT'] = 'dvi'
            if sysinfo['SYSTEM']['COMMAND'] == 'input_dp':
                sysinfo['SYSTEM']['CHAINPREVIOUS']['ON'] = sysinfo['SYSTEM']['CHAIN']['ON']
                sysinfo['SYSTEM']['CHAIN']['ON'] = 1
                if sysinfo['SYSTEM']['CHAINPREVIOUS']['ON'] == 0:
                    try:
                        if osplatform == 'linux':
                            with Timeout(10):
                                cmdresponse = changeinputall(sysinfo, inputcode)
                        else:
                            cmdresponse = changeinputall(sysinfo, inputcode)
                    except:
                        pass
                        msg = ('Error 4 in {0}'.format(gotthefunc))
                        sendlog(gotthefunc, msg, 40)
                        err = traceback.format_exc()
                        msg = ('Error 4 Detail: {0}'.format(err))
                        sendlog(gotthefunc, msg, 10)
                else:
                    try:
                        if osplatform == 'linux':
                            with Timeout(10):
                                cmdresponse = changeinput(sysinfo, inputcode)
                        else:
                            cmdresponse = changeinput(sysinfo, inputcode)
                    except:
                        pass
                        msg = ('Error 5 in {0}'.format(gotthefunc))
                        sendlog(gotthefunc, msg, 40)
                        err = traceback.format_exc()
                        msg = ('Error 5 Detail: {0}'.format(err))
                        sendlog(gotthefunc, msg, 10)
                update_dict(sysinfo, cmdresponse)
                sysinfo['SYSTEM']['BASEINPUT'] = 'dp'
            if sysinfo['SYSTEM']['COMMAND'] == 'input_hdmi' or sysinfo['SYSTEM']['COMMAND'] == 'input_hdmi1':
## Temporary until I can get this to only affect drequested screen numbers
                sysinfo['SYSTEM']['CHAINPREVIOUS']['ON'] = sysinfo['SYSTEM']['CHAIN']['ON']
                sysinfo['SYSTEM']['CHAIN']['ON'] = 1
                try:
                    if osplatform == 'linux':
                        with Timeout(10):
                            cmdresponse = changeinput(sysinfo, inputcode)
                    else:
                        cmdresponse = changeinput(sysinfo, inputcode)
                except:
                    pass
                    msg = ('Error 8 in {0}'.format(gotthefunc))
                    sendlog(gotthefunc, msg, 40)
                    err = traceback.format_exc()
                    msg = ('Error 8 Detail: {0}'.format(err))
                    sendlog(gotthefunc, msg, 10)
                update_dict(sysinfo, cmdresponse)
                sysinfo['SYSTEM']['BASEINPUT'] = 'hdmi'
            if sysinfo['SYSTEM']['COMMAND'] == 'input_hdmi2':
## Temporary until I can get this to only affect drequested screen numbers
                sysinfo['SYSTEM']['CHAINPREVIOUS']['ON'] = sysinfo['SYSTEM']['CHAIN']['ON']
                sysinfo['SYSTEM']['CHAIN']['ON'] = 1
                try:
                    if osplatform == 'linux':
                        with Timeout(10):
                            cmdresponse = changeinput(sysinfo, inputcode)
                    else:
                        cmdresponse = changeinput(sysinfo, inputcode)
                except:
                    pass
                    msg = ('Error 8 in {0}'.format(gotthefunc))
                    sendlog(gotthefunc, msg, 40)
                    err = traceback.format_exc()
                    msg = ('Error 8 Detail: {0}'.format(err))
                    sendlog(gotthefunc, msg, 10)
                update_dict(sysinfo, cmdresponse)
            if sysinfo['SYSTEM']['COMMAND'] == 'input_hdmi3':
## Temporary until I can get this to only affect drequested screen numbers
                sysinfo['SYSTEM']['CHAINPREVIOUS']['ON'] = sysinfo['SYSTEM']['CHAIN']['ON']
                sysinfo['SYSTEM']['CHAIN']['ON'] = 1
                try:
                    if osplatform == 'linux':
                        with Timeout(10):
                            cmdresponse = changeinput(sysinfo, inputcode)
                    else:
                        cmdresponse = changeinput(sysinfo, inputcode)
                except:
                    pass
                    msg = ('Error 8 in {0}'.format(gotthefunc))
                    sendlog(gotthefunc, msg, 40)
                    err = traceback.format_exc()
                    msg = ('Error 8 Detail: {0}'.format(err))
                    sendlog(gotthefunc, msg, 10)
                update_dict(sysinfo, cmdresponse)
            if sysinfo['SYSTEM']['COMMAND'] == 'input_hdmi4':
## Temporary until I can get this to only affect drequested screen numbers
                sysinfo['SYSTEM']['CHAINPREVIOUS']['ON'] = sysinfo['SYSTEM']['CHAIN']['ON']
                sysinfo['SYSTEM']['CHAIN']['ON'] = 1
                try:
                    if osplatform == 'linux':
                        with Timeout(10):
                            cmdresponse = changeinput(sysinfo, inputcode)
                    else:
                        cmdresponse = changeinput(sysinfo, inputcode)
                except:
                    pass
                    msg = ('Error 8 in {0}'.format(gotthefunc))
                    sendlog(gotthefunc, msg, 40)
                    err = traceback.format_exc()
                    msg = ('Error 8 Detail: {0}'.format(err))
                    sendlog(gotthefunc, msg, 10)
                update_dict(sysinfo, cmdresponse)
            if sysinfo['SYSTEM']['COMMAND'] == 'input_hdmi-all':
                sysinfo['SYSTEM']['CHAINPREVIOUS']['ON'] = sysinfo['SYSTEM']['CHAIN']['ON']
                sysinfo['SYSTEM']['CHAIN']['ON'] = 1
                try:
                    if osplatform == 'linux':
                        with Timeout(10):
                            cmdresponse = changeinputall(sysinfo, inputcode)
                    else:
                        cmdresponse = changeinputall(sysinfo, inputcode)
                except:
                    pass
                    msg = ('Error 9 in {0}'.format(gotthefunc))
                    sendlog(gotthefunc, msg, 40)
                    err = traceback.format_exc()
                    msg = ('Error 9 Detail: {0}'.format(err))
                    sendlog(gotthefunc, msg, 10)
                update_dict(sysinfo, cmdresponse)
                sysinfo['SYSTEM']['BASEINPUT'] = 'hdmi'
            if sysinfo['SYSTEM']['COMMAND'] == 'input_hdmi_splitter_4':
                sysinfo['SYSTEM']['CHAINPREVIOUS']['ON'] = sysinfo['SYSTEM']['CHAIN']['ON']
                sysinfo['SYSTEM']['CHAIN']['ON'] = 0
                try:
                    if osplatform == 'linux':
                        with Timeout(10):
                            cmdresponse = changeinputrange(sysinfo, inputcode, 4)
                    else:
                        cmdresponse = changeinputrange(sysinfo, inputcode, 4)
                except:
                    pass
                    msg = ('Error 10 in {0}'.format(gotthefunc))
                    sendlog(gotthefunc, msg, 40)
                    err = traceback.format_exc()
                    msg = ('Error 10 Detail: {0}'.format(err))
                    sendlog(gotthefunc, msg, 10)
                update_dict(sysinfo, cmdresponse)
            if sysinfo['SYSTEM']['COMMAND'] == 'input_hdmi_splitter':
                sysinfo['SYSTEM']['CHAINPREVIOUS']['ON'] = sysinfo['SYSTEM']['CHAIN']['ON']
                sysinfo['SYSTEM']['CHAIN']['ON'] = 0
                try:
                    if osplatform == 'linux':
                        with Timeout(10):
                            cmdresponse = changeinput(sysinfo, inputcode)
                    else:
                        cmdresponse = changeinput(sysinfo, inputcode)
                except:
                    pass
                    msg = ('Error 11 in {0}'.format(gotthefunc))
                    sendlog(gotthefunc, msg, 40)
                    err = traceback.format_exc()
                    msg = ('Error 11 Detail: {0}'.format(err))
                    sendlog(gotthefunc, msg, 10)
                update_dict(sysinfo, cmdresponse)
                sysinfo['SYSTEM']['BASEINPUT'] = 'hdmi_splitter'
            if sysinfo['SYSTEM']['COMMAND'] == 'input_hdmi_1a':
                sysinfo['SYSTEM']['CHAINPREVIOUS']['ON'] = sysinfo['SYSTEM']['CHAIN']['ON']
                sysinfo['SYSTEM']['CHAIN']['ON'] = 1
                ##### routelist can be [[1,'a'],[1,'b']] for multiple route changes
                routelist = [[1,'a']]
                try:
                    if osplatform == 'linux':
                        with Timeout(10):
                            cmdresponse = setmatrixroute(sysinfo['SYSTEM']['MATRIXIP'],sysinfo['SYSTEM']['MYIP'],routelist)
                    else:
                        cmdresponse = setmatrixroute(sysinfo['SYSTEM']['MATRIXIP'],sysinfo['SYSTEM']['MYIP'],routelist)
                except:
                    pass
                    msg = ('Error 20 in {0}'.format(gotthefunc))
                    sendlog(gotthefunc, msg, 40)
                    err = traceback.format_exc()
                    msg = ('Error 20 Detail: {0}'.format(err))
                    sendlog(gotthefunc, msg, 10)
#                update_dict(sysinfo, cmdresponse)
                sysinfo['SYSTEM']['BASEINPUT'] = 'hdmi_1a'
            """ 
            Add some tiling for matrix. Need to store current matrix routes and revert when tiling is done, like inputs.
            1) Save current routes
            2) Build route list
            3) Change matrix routes
            4) Set chain to 0
            5) tile on

            When tile is off
            1) Retreive previous route list
            2) Restore routes
            3) Tile off
            """
            if sysinfo['SYSTEM']['COMMAND'] == 'input_hdmi_7a':
                sysinfo['SYSTEM']['CHAINPREVIOUS']['ON'] = sysinfo['SYSTEM']['CHAIN']['ON']
                sysinfo['SYSTEM']['CHAIN']['ON'] = 1
                routelist = [[7,'a']]
                try:
                    if osplatform == 'linux':
                        with Timeout(10):
                            cmdresponse = setmatrixroute(sysinfo['SYSTEM']['MATRIXIP'],sysinfo['SYSTEM']['MYIP'],routelist)
                    else:
                        cmdresponse = setmatrixroute(sysinfo['SYSTEM']['MATRIXIP'],sysinfo['SYSTEM']['MYIP'],routelist)
                except:
                    pass
                    msg = ('Error 20 in {0}'.format(gotthefunc))
                    sendlog(gotthefunc, msg, 40)
                    err = traceback.format_exc()
                    msg = ('Error 20 Detail: {0}'.format(err))
                    sendlog(gotthefunc, msg, 10)
#                update_dict(sysinfo, cmdresponse)
                sysinfo['SYSTEM']['BASEINPUT'] = 'hdmi_7a'
            if sysinfo['SYSTEM']['COMMAND'] == 'input_hdmi_matrix':
                sysinfo['SYSTEM']['CHAINPREVIOUS']['ON'] = sysinfo['SYSTEM']['CHAIN']['ON']
                sysinfo['SYSTEM']['CHAIN']['ON'] = 0
                sysinfo['SYSTEM']['USEMATRIX'] = 1
                try:
                    if osplatform == 'linux':
                        with Timeout(10):
                            cmdresponse = changeinput(sysinfo, inputcode)
                    else:
                        cmdresponse = changeinput(sysinfo, inputcode)
                except:
                    pass
                    msg = ('Error 20 in {0}'.format(gotthefunc))
                    sendlog(gotthefunc, msg, 40)
                    err = traceback.format_exc()
                    msg = ('Error 20 Detail: {0}'.format(err))
                    sendlog(gotthefunc, msg, 10)
                update_dict(sysinfo, cmdresponse)
                sysinfo['SYSTEM']['BASEINPUT'] = 'hdmi_splitter'
            if sysinfo['SYSTEM']['COMMAND'] == 'input_option':
                sysinfo['SYSTEM']['CHAINPREVIOUS']['ON'] = sysinfo['SYSTEM']['CHAIN']['ON']
                sysinfo['SYSTEM']['CHAIN']['ON'] = 1
                try:
                    if osplatform == 'linux':
                        with Timeout(10):
                            cmdresponse = changeinput(sysinfo, inputcode)
                    else:
                        cmdresponse = changeinput(sysinfo, inputcode)
                except:
                    pass
                    msg = ('Error 12 in {0}'.format(gotthefunc))
                    sendlog(gotthefunc, msg, 40)
                    err = traceback.format_exc()
                    msg = ('Error 12 Detail: {0}'.format(err))
                    sendlog(gotthefunc, msg, 10)
                update_dict(sysinfo, cmdresponse)
            if sysinfo['SYSTEM']['COMMAND'] == 'tile_8_on':
                dbsuccess = 0
                while dbsuccess == 0:
                    try:
                        conn = sqlite3.connect(sysinfo['SYSTEM']['DATABASEFILE'])
                        c = conn.cursor()
                        c.execute('SELECT value FROM counters WHERE tags = ?', ('lasttileid',))
                    except sqlite3.OperationalError:
                        pass
                        msg = ('{}: Database locked (14). Trying again.',format(gotthefunc))
                        sendlog(gotthefunc, msg, 10)
                        sleep(0.5)
                    except:
                        pass
                        err = traceback.format_exc()
                        msg = ('Error in {0} Detail: {1}'.format(gotthefunc,err))
                        sendlog(gotthefunc, msg, 10)
                        sleep(0.5)
                    else:
                        row = c.fetchone()
                        dbsuccess = 1
                    finally:
                        conn.close()
                lasttileid = row[0]
                tileid = lasttileid + 1
                dbsuccess = 0
                while dbsuccess == 0:
                    try:
                        conn = sqlite3.connect(sysinfo['SYSTEM']['DATABASEFILE'])
                        c = conn.cursor()
                        c.execute('UPDATE counters SET value = ? WHERE tags = ?', (tileid,'lasttileid'))
                        conn.commit()
                    except sqlite3.OperationalError:
                        pass
                        msg = ('{}: Database locked (15). Trying again.',format(gotthefunc))
                        sendlog(gotthefunc, msg, 10)
                        sleep(0.5)
                    except:
                        pass
                        err = traceback.format_exc()
                        msg = ('Error in {0} Detail: {1}'.format(gotthefunc,err))
                        sendlog(gotthefunc, msg, 10)
                        sleep(0.5)
                    else:
                        dbsuccess = 1
                    finally:
                        conn.close()
                try:
                    if osplatform == 'linux':
                        with Timeout(130):
                            cmdresponse = buildtmfactory(sysinfo,4,2,tileid)
                    else:
                        cmdresponse = buildtmfactory(sysinfo,4,2,tileid)
                except:
                    pass
                    msg = ('Error 13 in {0}'.format(gotthefunc))
                    sendlog(gotthefunc, msg, 40)
                    err = traceback.format_exc()
                    msg = ('Error 13 Detail: {0}'.format(err))
                    sendlog(gotthefunc, msg, 10)
                msg = cmdresponse
                sendlog(gotthefunc, msg, 10)
                update_dict(sysinfo, cmdresponse)
                sysinfo['SYSTEM']['TILE'] = 8
            if sysinfo['SYSTEM']['COMMAND'] == 'tile_9_on':
                msg = ('Entered tile_9_on command section')
                sendlog(gotthefunc, msg, 10)
                displaylist = [1,2,3,4,5,6,7,8,9]
                if sysinfo['WALL']['NUMBERING'] == 'L2R':
                    if sysinfo['WALL']['LAYOUT'] == '4x3':
                        if sysinfo['SYSTEM']['TARGET'] == 1:
                            displaylist = [1,2,3,5,6,7,9,10,11]
                        if sysinfo['SYSTEM']['TARGET'] == 2:
                            displaylist = [2,3,4,6,7,8,10,11,12]
                sysinfo['SYSTEM']['CHAIN']['ON'] = 1
                dbsuccess = 0
                while dbsuccess == 0:
                    try:
                        conn = sqlite3.connect(sysinfo['SYSTEM']['DATABASEFILE'])
                        c = conn.cursor()
                        c.execute('SELECT value FROM counters WHERE tags = ?', ('lasttileid',))
                    except sqlite3.OperationalError:
                        pass
                        msg = ('{}: Database locked (16). Trying again.',format(gotthefunc))
                        sendlog(gotthefunc, msg, 10)
                        sleep(0.5)
                    except:
                        pass
                        err = traceback.format_exc()
                        msg = ('Error in {0} Detail: {1}'.format(gotthefunc,err))
                        sendlog(gotthefunc, msg, 10)
                        sleep(0.5)
                    else:
                        row = c.fetchone()
                        dbsuccess = 1
                    finally:
                        conn.close()
                lasttileid = row[0]
                tileid = lasttileid + 1
                dbsuccess = 0
                while dbsuccess == 0:
                    try:
                        conn = sqlite3.connect(sysinfo['SYSTEM']['DATABASEFILE'])
                        c = conn.cursor()
                        c.execute('UPDATE counters SET value = ? WHERE tags = ?', (tileid,'lasttileid'))
                        conn.commit()
                    except sqlite3.OperationalError:
                        pass
                        msg = ('{}: Database locked (17). Trying again.',format(gotthefunc))
                        sendlog(gotthefunc, msg, 10)
                        sleep(0.5)
                    except:
                        pass
                        err = traceback.format_exc()
                        msg = ('Error in {0} Detail: {1}'.format(gotthefunc,err))
                        sendlog(gotthefunc, msg, 10)
                        sleep(0.5)
                    else:
                        dbsuccess = 1
                        conn.close()
                try:
                    if osplatform == 'linux':
                        with Timeout(130):
                            cmdresponse = buildtmfactory(sysinfo,3,3,tileid,displaylist)
                    else:
                        cmdresponse = buildtmfactory(sysinfo,3,3,tileid,displaylist)
                except:
                    pass
                    msg = ('Error 13 in {0}'.format(gotthefunc))
                    sendlog(gotthefunc, msg, 40)
                    err = traceback.format_exc()
                    msg = ('Error 13 Detail: {0}'.format(err))
                    sendlog(gotthefunc, msg, 10)
                msg = cmdresponse
                sendlog(gotthefunc, msg, 10)
                update_dict(sysinfo, cmdresponse)
                sysinfo['SYSTEM']['TILE'] = 9
            if sysinfo['SYSTEM']['COMMAND'] == 'tile_12_on':
                msg = ('Entered tile_12_on command section')
                sendlog(gotthefunc, msg, 10)
                displaylist = []
                if sysinfo['WALL']['NUMBERING'] == 'L2R':
                    if sysinfo['WALL']['LAYOUT'] == '4x3':
                        if sysinfo['SYSTEM']['TARGET'] == 1:
                            displaylist = [1,2,3,4,5,6,7,8,9,10,11,12]
                sysinfo['SYSTEM']['CHAIN']['ON'] = 1
                dbsuccess = 0
                while dbsuccess == 0:
                    try:
                        conn = sqlite3.connect(sysinfo['SYSTEM']['DATABASEFILE'])
                        c = conn.cursor()
                        c.execute('SELECT value FROM counters WHERE tags = ?', ('lasttileid',))
                    except sqlite3.OperationalError:
                        pass
                        msg = ('{}: Database locked (18). Trying again.',format(gotthefunc))
                        sendlog(gotthefunc, msg, 10)
                        sleep(0.5)
                    except:
                        pass
                        err = traceback.format_exc()
                        msg = ('Error in {0} Detail: {1}'.format(gotthefunc,err))
                        sendlog(gotthefunc, msg, 10)
                        sleep(0.5)
                    else:
                        row = c.fetchone()
                        dbsuccess = 1
                    finally:
                        conn.close()
                lasttileid = row[0]
                tileid = lasttileid + 1
                dbsuccess = 0
                while dbsuccess == 0:
                    try:
                        conn = sqlite3.connect(sysinfo['SYSTEM']['DATABASEFILE'])
                        c = conn.cursor()
                        c.execute('UPDATE counters SET value = ? WHERE tags = ?', (tileid,'lasttileid'))
                        conn.commit()
                    except sqlite3.OperationalError:
                        pass
                        msg = ('{}: Database locked (19). Trying again.',format(gotthefunc))
                        sendlog(gotthefunc, msg, 10)
                        sleep(0.5)
                    except:
                        pass
                        err = traceback.format_exc()
                        msg = ('Error in {0} Detail: {1}'.format(gotthefunc,err))
                        sendlog(gotthefunc, msg, 10)
                        sleep(0.5)
                    else:
                        dbsuccess = 1
                    finally:
                        conn.close()
                try:
                    if osplatform == 'linux':
                        with Timeout(130):
                            cmdresponse = buildtmfactory(sysinfo,4,3,tileid)
                    else:
                        cmdresponse = buildtmfactory(sysinfo,4,3,tileid)
                except:
                    pass
                    msg = ('Error 13 in {0}'.format(gotthefunc))
                    sendlog(gotthefunc, msg, 40)
                    err = traceback.format_exc()
                    msg = ('Error 13 Detail: {0}'.format(err))
                    sendlog(gotthefunc, msg, 10)
                msg = cmdresponse
                sendlog(gotthefunc, msg, 10)
                update_dict(sysinfo, cmdresponse)
                sysinfo['SYSTEM']['TILE'] = 12
            if sysinfo['SYSTEM']['COMMAND'] == 'tile_16_on':
                msg = ('Entered tile_16_on command section')
                sendlog(gotthefunc, msg, 10)
                displaylist = None
                if sysinfo['WALL']['NUMBERING'] == 'L2R':
                    if sysinfo['WALL']['LAYOUT'] == '4x3':
                        if sysinfo['SYSTEM']['TARGET'] == 1:
                            displaylist = []
                            displaylist = [1,2,3,4,5,6,7,8,9,10,11,12]
                sysinfo['SYSTEM']['CHAIN']['ON'] = 1
                dbsuccess = 0
                while dbsuccess == 0:
                    try:
                        conn = sqlite3.connect(sysinfo['SYSTEM']['DATABASEFILE'])
                        c = conn.cursor()
                        c.execute('SELECT value FROM counters WHERE tags = ?', ('lasttileid',))
                    except sqlite3.OperationalError:
                        pass
                        msg = ('{}: Database locked (20). Trying again.',format(gotthefunc))
                        sendlog(gotthefunc, msg, 10)
                        sleep(0.5)
                    except:
                        pass
                        err = traceback.format_exc()
                        msg = ('Error in {0} Detail: {1}'.format(gotthefunc,err))
                        sendlog(gotthefunc, msg, 10)
                        sleep(0.5)
                    else:
                        row = c.fetchone()
                        dbsuccess = 1
                    finally:
                        conn.close()
                lasttileid = row[0]
                tileid = lasttileid + 1
                dbsuccess = 0
                while dbsuccess == 0:
                    try:
                        conn = sqlite3.connect(sysinfo['SYSTEM']['DATABASEFILE'])
                        c = conn.cursor()
                        c.execute('UPDATE counters SET value = ? WHERE tags = ?', (tileid,'lasttileid'))
                        conn.commit()
                    except sqlite3.OperationalError:
                        pass
                        msg = ('{}: Database locked (21). Trying again.',format(gotthefunc))
                        sendlog(gotthefunc, msg, 10)
                        sleep(0.5)
                    except:
                        pass
                        err = traceback.format_exc()
                        msg = ('Error in {0} Detail: {1}'.format(gotthefunc,err))
                        sendlog(gotthefunc, msg, 10)
                        sleep(0.5)
                    else:
                        dbsuccess = 1
                    finally:
                        conn.close()
                try:
                    if osplatform == 'linux':
                        with Timeout(130):
                            cmdresponse = buildtmfactory(sysinfo,4,4,tileid,displaylist)
                    else:
                        cmdresponse = buildtmfactory(sysinfo,4,4,tileid,displaylist)
                except:
                    pass
                    msg = ('Error 13 in {0}'.format(gotthefunc))
                    sendlog(gotthefunc, msg, 40)
                    err = traceback.format_exc()
                    msg = ('Error 13 Detail: {0}'.format(err))
                    sendlog(gotthefunc, msg, 10)
                msg = cmdresponse
                sendlog(gotthefunc, msg, 10)
                update_dict(sysinfo, cmdresponse)
                sysinfo['SYSTEM']['TILE'] = 16
            if sysinfo['SYSTEM']['COMMAND'] == 'tile_on':
                msg = ('Entered tile_on command section')
                sendlog(gotthefunc, msg, 10)
                displaylist = []
                if sysinfo['WALL']['NUMBERING'] == 'L2R':
                    if sysinfo['WALL']['LAYOUT'] == '2x2':
                        if sysinfo['SYSTEM']['TARGET'] == 1:
                            displaylist = [1,2,3,4]
                    if sysinfo['WALL']['LAYOUT'] == '3x2':
                        if sysinfo['SYSTEM']['TARGET'] == 1:
                            displaylist = [1,2,4,5]
                        if sysinfo['SYSTEM']['TARGET'] == 2:
                            displaylist = [2,3,5,6]
                    if sysinfo['WALL']['LAYOUT'] == '4x2':
                        if sysinfo['SYSTEM']['TARGET'] == 1:
                            displaylist = [1,2,5,6]
                        if sysinfo['SYSTEM']['TARGET'] == 2:
                            displaylist = [2,3,6,7]
                        if sysinfo['SYSTEM']['TARGET'] == 3:
                            displaylist = [3,4,7,8]
                    if sysinfo['WALL']['LAYOUT'] == '6x2':
                        if sysinfo['SYSTEM']['TARGET'] == 1:
                            displaylist = [1,2,7,8]
                        if sysinfo['SYSTEM']['TARGET'] == 2:
                            displaylist = [2,3,8,9]
                        if sysinfo['SYSTEM']['TARGET'] == 3:
                            displaylist = [3,4,9,10]
                        if sysinfo['SYSTEM']['TARGET'] == 4:
                            displaylist = [4,5,10,11]
                        if sysinfo['SYSTEM']['TARGET'] == 5:
                            displaylist = [5,6,11,12]
                    if sysinfo['WALL']['LAYOUT'] == '4x3':
                        if sysinfo['SYSTEM']['TARGET'] == 1:
                            displaylist = [1,2,5,6]
                        if sysinfo['SYSTEM']['TARGET'] == 2:
                            displaylist = [2,3,6,7]
                        if sysinfo['SYSTEM']['TARGET'] == 3:
                            displaylist = [3,4,7,8]
                        if sysinfo['SYSTEM']['TARGET'] == 5:
                            displaylist = [5,6,9,10]
                        if sysinfo['SYSTEM']['TARGET'] == 7:
                            displaylist = [7,8,11,12]                        
                    if sysinfo['SYSTEM']['USEMATRIX'] == 1:
                        for displayid in displaylist:
                            outputletter = chr(96 + displayid)
                            sysinfo['SYSTEM']['MATRIXCOMMANDS'].append([d,'{}'.format(outputletter)])
                        sysinfo['SYSTEM']['CHAIN']['ON'] = 0
                    else:
                        sysinfo['SYSTEM']['CHAIN']['ON'] = 1
                else:
                    d = sysinfo['SYSTEM']['TARGET']
                    t = d
                    while t < d+4:
                        # print(t)
                        # print(displaylist)
                        displaylist.append(t)
                        t += 1
                    if sysinfo['SYSTEM']['USEMATRIX'] == 1:
                        outputnum = d
                        sysinfo['SYSTEM']['MATRIXCOMMANDS'] = []
                        while outputnum < d+4:
                            outputletter = chr(96 + outputnum)
                            sysinfo['SYSTEM']['MATRIXCOMMANDS'].append([d,'{}'.format(outputletter)])
                            outputnum += 1
                        sysinfo['SYSTEM']['CHAIN']['ON'] = 0
                    else:
                        sysinfo['SYSTEM']['CHAIN']['ON'] = 1
                dbsuccess = 0
                while dbsuccess == 0:
                    try:
                        conn = sqlite3.connect(sysinfo['SYSTEM']['DATABASEFILE'])
                        c = conn.cursor()
                        c.execute('SELECT value FROM counters WHERE tags = ?', ('lasttileid',))
                    except sqlite3.OperationalError:
                        pass
                        msg = ('{}: Database locked (22). Trying again.',format(gotthefunc))
                        sendlog(gotthefunc, msg, 10)
                        sleep(0.5)
                    except:
                        pass
                        err = traceback.format_exc()
                        msg = ('Error in {0} Detail: {1}'.format(gotthefunc,err))
                        sendlog(gotthefunc, msg, 10)
                        sleep(0.5)
                    else:
                        row = c.fetchone()
                        dbsuccess = 1
                    finally:
                        conn.close()
                lasttileid = row[0]
                tileid = lasttileid + 1
                dbsuccess = 0
                while dbsuccess == 0:
                    try:
                        conn = sqlite3.connect(sysinfo['SYSTEM']['DATABASEFILE'])
                        c = conn.cursor()
                        c.execute('UPDATE counters SET value = ? WHERE tags = ?', (tileid,'lasttileid'))
                        conn.commit()
                    except sqlite3.OperationalError:
                        pass
                        msg = ('{}: Database locked (23). Trying again.',format(gotthefunc))
                        sendlog(gotthefunc, msg, 10)
                        sleep(0.5)
                    except:
                        pass
                        err = traceback.format_exc()
                        msg = ('Error in {0} Detail: {1}'.format(gotthefunc,err))
                        sendlog(gotthefunc, msg, 10)
                        sleep(0.5)
                    else:
                        dbsuccess = 1
                    finally:
                        conn.close()
                '''
                    checking for displays already tiled - need to figure out what happens when someone accidentally sends
                    a tile command for the same displays already in the same tile. We don't want to force an untile to
                    retile the same way. for now, we'll force an untile just because of early development.
                '''
                for x in displaylist:
                    dbsuccess = 0
                    while dbsuccess == 0:
                        try:
                            conn = sqlite3.connect(sysinfo['SYSTEM']['DATABASEFILE'])
                            c = conn.cursor()
                            c.execute('SELECT tileid from tiles WHERE member=?', (x,))
                        except sqlite3.OperationalError:
                            pass
                            msg = ('{}: Database locked (24). Trying again.',format(gotthefunc))
                            sendlog(gotthefunc, msg, 10)
                            sleep(0.5)
                        except:
                            pass
                            err = traceback.format_exc()
                            msg = ('Error in {0} Detail: {1}'.format(gotthefunc,err))
                            sendlog(gotthefunc, msg, 10)
                            sleep(0.5)
                        else:
                            row = c.fetchone()
                            dbsuccess = 1
                        finally:
                            conn.close()
                    if row:
                        cmdresponse = disabletmfactory(sysinfo,row[0],0)
                try:
                    if osplatform == 'linux':
                        with Timeout(30):
                            if displaylist:
                                cmdresponse = buildtmfactory(sysinfo,2,2,tileid,displaylist)
                            else:
                                cmdresponse = buildtmfactory(sysinfo,2,2,tileid)
                    else:
                        if displaylist:
                            cmdresponse = buildtmfactory(sysinfo,2,2,tileid,displaylist)
                        else:
                            cmdresponse = buildtmfactory(sysinfo,2,2,tileid)
                except:
                    pass
                    msg = ('Error 14 in {0}'.format(gotthefunc))
                    sendlog(gotthefunc, msg, 40)
                    err = traceback.format_exc()
                    msg = ('Error 14 Detail: {0}'.format(err))
                    sendlog(gotthefunc, msg, 10)
                msg = cmdresponse
                sendlog(gotthefunc, msg, 10)
                update_dict(sysinfo, cmdresponse)
                sysinfo['SYSTEM']['TILE'] = 4
            if sysinfo['SYSTEM']['COMMAND'] == 'tile_off':
                dbsuccess = 0
                while dbsuccess == 0:
                    try:
                        conn = sqlite3.connect(sysinfo['SYSTEM']['DATABASEFILE'])
                        c = conn.cursor()
                        c.execute('SELECT tileid from tiles WHERE member = ?', (sysinfo['SYSTEM']['TARGET'], ))
                    except sqlite3.OperationalError:
                        pass
                        msg = ('{}: Database locked (25). Trying again.',format(gotthefunc))
                        sendlog(gotthefunc, msg, 10)
                        sleep(0.5)
                    except:
                        pass
                        err = traceback.format_exc()
                        msg = ('Error in {0} Detail: {1}'.format(gotthefunc,err))
                        sendlog(gotthefunc, msg, 10)
                        sleep(0.5)
                    else:
                        row = c.fetchone()
                        dbsuccess = 1
                    finally:
                        conn.close()
                if row:
                    try:
                        if osplatform == 'linux':
                            with Timeout(30):
                                cmdresponse = disabletmfactory(sysinfo,row[0])
                        else:
                            cmdresponse = disabletmfactory(sysinfo,row[0])
                    except:
                        pass
                        msg = ('Error 14 in {0}'.format(gotthefunc))
                        sendlog(gotthefunc, msg, 40)
                        err = traceback.format_exc()
                        msg = ('Error 14 Detail: {0}'.format(err))
                        sendlog(gotthefunc, msg, 10)
                else:
                    msg = ('No tile found for target {}'.format(sysinfo['SYSTEM']['TARGET']))
                    sendlog(gotthefunc, msg, 40)     
            if sysinfo['SYSTEM']['COMMAND'].startswith('volume'):
                vol = sysinfo['SYSTEM']['COMMAND'].split("_")
                try:
                    if osplatform == 'linux':
                        with Timeout(10):
                            cmdresponse = changevolume(sysinfo)
                    else:
                        cmdresponse = changevolume(sysinfo)
                except:
                    pass
                    msg = ('Error 17 in {0}'.format(gotthefunc))
                    sendlog(gotthefunc, msg, 40)
                    err = traceback.format_exc()
                    msg = ('Error 17 Detail: {0}'.format(err))
                    sendlog(gotthefunc, msg, 10)
                update_dict(sysinfo, cmdresponse)
                msg = cmdresponse
                sendlog(gotthefunc, msg, 10)
#            if sysinfo['SYSTEM']['PLATFORM'].lower() == 'lava':
            if 'lava' in sysinfo['SYSTEM']['PLATFORM'].lower() or sysinfo['SYSTEM']['PLATFORM'].lower() == 'onprem' or sysinfo['SYSTEM']['PLATFORM'].lower() == 'on-prem':
                if 'power' in sysinfo['SYSTEM']['COMMAND']:
                    power = sysinfo['SYSTEM']['COMMAND'].split('_')
                    try:
                        if osplatform == 'linux':
                            with Timeout(10):
                                if power[1] == 'off':
                                    changepower(sysinfo, 0)
                                if power[1] == 'on':
                                    changepower(sysinfo, 1)
                        else:
                            if power[1] == 'off':
                                changepower(sysinfo, 0)
                            if power[1] == 'on':
                                changepower(sysinfo, 1)
                    except:
                        pass
                        msg = ('Error 5 in {0}'.format(gotthefunc))
                        sendlog(gotthefunc, msg, 40)
                        err = traceback.format_exc()
                        msg = ('Error 5 Detail: {0}'.format(err))
                        sendlog(gotthefunc, msg, 10)
#                    update_dict(sysinfo, cmdresponse)
            if sysinfo['SYSTEM']['PLATFORM'].lower() == 'de':
                if sysinfo['SYSTEM']['COMMAND'] == 'display_all_power_off':
                    try:
                        if osplatform == 'linux':
                            with Timeout(10):
                                changepower(sysinfo, 0)
                        else:
                            changepower(sysinfo, 0)
                    except:
                        pass
                        msg = ('Error 18 in {0}'.format(gotthefunc))
                        sendlog(gotthefunc, msg, 40)
                        err = traceback.format_exc()
                        msg = ('Error 18 Detail: {0}'.format(err))
                        sendlog(gotthefunc, msg, 10)
                if sysinfo['SYSTEM']['COMMAND'] == 'display_all_power_on':
                    try:
                        if osplatform == 'linux':
                            with Timeout(10):
                                changepower(sysinfo, 1)
                        else:
                            changepower(sysinfo, 1)
                    except:
                        pass
                        msg = ('Error 19 in {0}'.format(gotthefunc))
                        sendlog(gotthefunc, msg, 40)
                        err = traceback.format_exc()
                        msg = ('Error 19 Detail: {0}'.format(err))
                        sendlog(gotthefunc, msg, 10)
            if sysinfo['SYSTEM']['COMMAND'] == 'nexp_reboot':
                msg = 'Reboot function disabled'
                sendlog(gotthefunc, msg, 10)
#                controller_reboot() 
                
#            sortedresults = collections.OrderedDict(sorted(sysinfo.items()))
#            for key,val in sortedresults.items():
#                msg = ("{0} = {1}".format(key,val))
#                sendlog(gotthefunc, msg, 10)
            savestate(sysinfo)
        else:
            msg = "Command is null. Pass."
            sendlog(gotthefunc, msg, 10)
            pass
            
        sleep(int(sysinfo['SYSTEM']['INTERVAL']))
        if csloop >= 60:
            savestate(sysinfo)
            csloop = 0
        else:
            csloop += 1
        dbsuccess = 0
        while dbsuccess == 0:
            try:
                conn = sqlite3.connect(sysinfo['SYSTEM']['DATABASEFILE'])
                c = conn.cursor()
                conn.commit()
            except sqlite3.OperationalError:
                pass
                msg = ('{}: Database locked (26). Trying again.',format(gotthefunc))
                sendlog(gotthefunc, msg, 10)
                sleep(0.5)
            except:
                pass
                err = traceback.format_exc()
                msg = ('Error in {0} Detail: {1}'.format(gotthefunc,err))
                sendlog(gotthefunc, msg, 10)
                sleep(0.5)
            else:
                dbsuccess = 1
                conn.close()
            
def iswallalive(sysinfo,iplist):
    gotthefunc = inspect.stack()[0][3]
    msg = ('Entered {} function'.format(gotthefunc))
    sendlog(gotthefunc, msg, 10)
    socketnum = 0
    walldown = 0
    pingqueue = Queue()
    pingworkers = []
    for ipid, ipaddr in iplist.items():
        now = datetime.datetime.now()
        pingworker = Process(target=ping, args=(sysinfo, ipaddr, socketnum, pingqueue))
        pingworkers.append(pingworker)
        pingworker.start()
        socketnum += 1
    pingresults = {}
    for i in range(socketnum):
        update_dict(pingresults, pingqueue.get())
    for w in pingworkers:
        w.join()
    sortedresults = collections.OrderedDict(sorted(pingresults.items()))
    for key,val in sortedresults.items():
        msg = ('{0} = {1}'.format(key,val))
        sendlog(gotthefunc, msg, 10)
        if val['UP'] == False:
            subject = ('DISPLAY {} DOWN!'.format(key))
            msg = ('DISPLAY {} DOWN!'.format(key))
            sendemail(sysinfo,subject,msg)
            sendlog(gotthefunc, msg, 50)
            sleep(5)
            walldown = 1
    msg = ('Exited {} function'.format(gotthefunc))
    sendlog(gotthefunc, msg, 10)
    return(walldown)

def main(application_path=None):
    gotthefunc = inspect.stack()[0][3]
    msg = ('Entered {} function'.format(gotthefunc))
    
    sysinfo = {}
    sysinfo['PLATFORM'] = {}
    sysinfo['SYSTEM'] = {}
    sysinfo['WALL'] = {}
    sysinfo['SYSTEM']['CHAIN'] = {}
    sysinfo['SYSTEM']['CHAINPREVIOUS'] = {}
    sysinfo['SYSTEM']['LASTHEADDATE'] = None
    sysinfo['SYSTEM']['SERIALPORT'] = None
    sysinfo['SYSTEM']['TOKEN'] = None
    sysinfo['SYSTEM']['MAC'] = None
    
    if osplatform == 'linux':
        sysinfo['SYSTEM']['DATABASEFILE'] = ('/var/lib/lavacontrols/lavacontrols.db')
        sysinfo['SYSTEM']['LAVACONTROLSCONFIGFILE'] = ('/etc/lavacontrols/lavacontrols.conf')
        sysinfo['SYSTEM']['LAVACONTROLSLOGFILE'] = ('/var/log/lavacontrols/lavacontrols.log')
        sysinfo['SYSTEM']['LAVACONTROLSLOCKFILE'] = ('/var/lib/lavacontrols/lavacontrols.run')
        sysinfo['SYSTEM']['LAVACONTROLSNETFILE'] = ('/var/lib/lavacontrols/lavacontrols.netinfo')
        sysinfo['SYSTEM']['LAVACONTROLSSTATEFILE'] = ('{}\\db\\lavacontrols.state'.format(application_path))
    elif osplatform == 'windows':
        if not application_path:
            application_path = os.getcwd()
        sysinfo['SYSTEM']['DATABASEFILE'] = ('{}\\db\\lavacontrols.db'.format(application_path))
        sysinfo['SYSTEM']['LAVACONTROLSCONFIGFILE'] = ('{}\\conf\\lavacontrols.conf'.format(application_path))
        sysinfo['SYSTEM']['LAVACONTROLSLOGFILE'] = ('{}\\logs\\lavacontrols.log'.format(application_path))
#        sysinfo['SYSTEM']['LAVACONTROLSLOGFILE'] = ('{}/logs/lavacontrols.log'.format(application_path))
        sysinfo['SYSTEM']['LAVACONTROLSLOCKFILE'] = ('{}\\db\\lavacontrols.run'.format(application_path))
        sysinfo['SYSTEM']['LAVACONTROLSNETFILE'] = ('{}\\db\\lavacontrols.netinfo'.format(application_path))
        sysinfo['SYSTEM']['LAVACONTROLSSTATEFILE'] = ('{}\\db\\lavacontrols.state'.format(application_path))

    parser = argparse.ArgumentParser(description='LAVA Controls')
    parser.add_argument('--console', action="store_true", default=False, dest='consolelogs', help = 'Output logs to console')
    cliargs = parser.parse_args()

    timeout = 10
    # socket.setdefaulttimeout(timeout)
    mainworkers = []
    try:
        mainworker = Process(target=logserver, args=(sysinfo,))
        mainworkers.append(mainworker)
        mainworker.start()
    except:
        err = traceback.format_exc()
        msg = ('Error Detail: {0}'.format(err))
        sendlog(gotthefunc, msg, 10)
        sys.exit()

#    logworker = Process(target=logserver)
#    logworker.start()

    sleep(5)
    
    logger = logging.getLogger('main')
    sock = logging.handlers.SocketHandler('localhost', 9042)
    logger.addHandler(sock)
    if cliargs.consolelogs:
        consolelog = logging.StreamHandler(sys.stdout)
        logger.addHandler(consolelog)
    logger.setLevel(logging.DEBUG)
    
    sleep(5)

    msg = 'LAVA Controls {} Startup'.format(version())
    sendlog(gotthefunc, msg, 10)
    
    try:
        conn = sqlite3.connect(sysinfo['SYSTEM']['DATABASEFILE'])
        c = conn.cursor()
    except:
        msg = ('Cannot open database {}'.format(sysinfo['SYSTEM']['DATABASEFILE']))
        sendlog(gotthefunc, msg, 10)
        err = traceback.format_exc()
        msg = ('Error Detail: {0}'.format(err))
        sendlog(gotthefunc, msg, 10)
    else:
        msg = ('Startup database open successful.'.format(sysinfo['SYSTEM']['DATABASEFILE']))
        sendlog(gotthefunc, msg, 10)

    # Read config
    config = configparser.ConfigParser()
    try:
        config.read([sysinfo['SYSTEM']['LAVACONTROLSCONFIGFILE']])
    except configparser.Error as e:
        msg = ('Unable to read configuration file {}! Halting!'.format(sysinfo['SYSTEM']['LAVACONTROLSCONFIGFILE']))
        if osplatform == 'linux':
            sendlog(gotthefunc, msg, 10)
        sys.exit()
    except:
        msg = ('Error in {0} Reading Config! Halting!'.format(gotthefunc))
        sendlog(gotthefunc, msg, 10)
        err = traceback.format_exc()
        msg = ('Error Detail: {0}'.format(err))
        sendlog(gotthefunc, msg, 10)
        sys.exit()
    else:
        msg = ('CONFIG: Loaded config file')
        sendlog(gotthefunc, msg, 10)
    #get platform type, whether new LAVA Controls API or legacy display engine
    try:
        sysinfo['SYSTEM']['PLATFORM'] = config.get('system', 'platform')
    except (configparser.NoOptionError, configparser.InterpolationMissingOptionError):
        msg = ('No platform type in configuration file! Halting!')
        sendlog(gotthefunc, msg, 10)
        sys.exit()
    except configparser.Error as e:
        msg = ('Config read entry system platform type error! Defaulting to lava!')
        sendlog(gotthefunc, msg, 10)
        sys.exit()
    except:
        msg = ('Error in {0} Reading Config! Defaulting to lava!'.format(gotthefunc))
        sendlog(gotthefunc, msg, 40)
        err = traceback.format_exc()
        sendlog(gotthefunc, msg, 10)
        sys.exit()
    else:
        if sysinfo['SYSTEM']['PLATFORM'] == 'de':
            sysinfo['PLATFORM']['API'] = 'https://cloud.ideacage.com'
        elif sysinfo['SYSTEM']['PLATFORM'] == 'lava':
            sysinfo['PLATFORM']['API'] = 'https://endpoint.lavacontrols.com'
        elif sysinfo['SYSTEM']['PLATFORM'] == 'lava-dev':
            sysinfo['PLATFORM']['API'] = 'https://api-dev.lavacontrols.com'
        elif sysinfo['SYSTEM']['PLATFORM'] == 'onprem' or sysinfo['SYSTEM']['PLATFORM'] == 'on-prem':
            try:
                sysinfo['PLATFORM']['API'] = config.get('platform', 'api')
            except:
                msg = ('Error in {0} Reading Config! Cannot read onprem api server entry. Halting.'.format(gotthefunc))
                sendlog(gotthefunc, msg, 10)
                err = traceback.format_exc()
                msg = ('Error Detail: {0}'.format(err))
                sendlog(gotthefunc, msg, 10)
                sys.exit()
        else:
            sysinfo['SYSTEM']['PLATFORM'] = 'lava'
            sysinfo['PLATFORM']['API'] = 'https://endpoint.lavacontrols.com'
        msg = ('CONFIG: Loaded platform type {} with API {}'.format(sysinfo['SYSTEM']['PLATFORM'], sysinfo['PLATFORM']['API']))
        sendlog(gotthefunc, msg, 10)
    while True:
        try:
            sysinfo['SYSTEM']['MAC'], sysinfo['SYSTEM']['MYIP'], sysinfo['SYSTEM']['IFACE'] = netinfo(sysinfo)
        except:
            msg = ('Error in {0} calling netinfo! Halting!'.format(gotthefunc))
            sendlog(gotthefunc, msg, 10)
            err = traceback.format_exc()
            msg = ('Error Detail: {0}'.format(err))
            sendlog(gotthefunc, msg, 10)
            sleep(5)
        else:
            msg = ('CONFIG: Got MAC {} and IP {} IFACE {}'.format(sysinfo['SYSTEM']['MAC'], sysinfo['SYSTEM']['MYIP'], sysinfo['SYSTEM']['IFACE']))
            sendlog(gotthefunc, msg, 10)
            break
    try:
        sysinfo['SYSTEM']['INTERVAL'] = config.get('system', 'interval')
    except (configparser.NoOptionError, configparser.InterpolationMissingOptionError):
        msg = ('No interval specified in configuration file. Defaulting to 1!')
        sendlog(gotthefunc, msg, 10)
        sysinfo['SYSTEM']['INTERVAL'] = '1'
        pass
    except configparser.Error as e:
        sysinfo['SYSTEM']['INTERVAL'] = '1'
    except:
        msg = ('Error in {0} Reading Config! Halting!'.format(gotthefunc))
        sendlog(gotthefunc, msg, 10)
        err = traceback.format_exc()
        msg = ('Error Detail: {0}'.format(err))
        sendlog(gotthefunc, msg, 10)
        sysinfo['SYSTEM']['INTERVAL'] = '1'
    else:
        msg = ('CONFIG: Got interval')
        sendlog(gotthefunc, msg, 10)
    try:
        sysinfo['SYSTEM']['LOGLEVEL'] = config.get('system', 'loglevel')
    except (configparser.NoOptionError, configparser.InterpolationMissingOptionError):
        msg = ('No logging type specified in configuration file. Defaulting to INFO!')
        sendlog(gotthefunc, msg, 10)
        sysinfo['SYSTEM']['LOGLEVEL'] = '20'
        pass
    except configparser.Error as e:
        msg = ('Config read entry system loglevel error! Halting!')
        sendlog(gotthefunc, msg, 10)
        sys.exit()
    except:
        msg = ('Error in {0} Reading Config! Halting!'.format(gotthefunc))
        sendlog(gotthefunc, msg, 10)
        err = traceback.format_exc()
        msg = ('Error Detail: {0}'.format(err))
        sendlog(gotthefunc, msg, 10)
        sys.exit()
    else:
        msg = ('CONFIG: Got logging level')
        sendlog(gotthefunc, msg, 10)
    try:
        sysinfo['SYSTEM']['EMAIL'] = [e.strip() for e in config.get('system', 'emailnotification').split(',')]
    except (configparser.NoOptionError, configparser.InterpolationMissingOptionError):
        msg = ('No email(s) for notifications specified in configuration file. Continuing with no notifications.')
        sendlog(gotthefunc, msg, 10)
        sysinfo['SYSTEM']['EMAIL'] = ['service@lavacontrols.com']
        pass
    except configparser.Error as e:
        msg = ('Config read entry system email notification error! Clearing entry.')
        sendlog(gotthefunc, msg, 10)
        sysinfo['SYSTEM']['EMAIL'] = ['service@lavacontrols.com']
        pass
    except:
        msg = ('Unknown Error in {0} Reading Config! Halting!'.format(gotthefunc))
        sendlog(gotthefunc, msg, 10)
        err = traceback.format_exc()
        msg = ('Unknown Error in {0} Detail: {1}'.format(gotthefunc,err))
        print(msg)
        sendlog(gotthefunc, msg, 10)
        sys.exit()
    try:
        sysinfo['SYSTEM']['SMTPHOST'] = config.get('system', 'smtphost')
    except (configparser.NoOptionError, configparser.InterpolationMissingOptionError):
        msg = ('No smtp hosts for notifications specified in configuration file. Default to localhost.')
        sendlog(gotthefunc, msg, 10)
        sysinfo['SYSTEM']['SMTPHOST'] = 'localhost'
        pass
    except configparser.Error as e:
        msg = ('Config read entry system email notification error! Clearing entry.')
        sendlog(gotthefunc, msg, 10)
        sysinfo['SYSTEM']['SMTPHOST'] = 'localhost'
        pass
    except:
        msg = ('Unknown Error in {0} Reading Config! Halting!'.format(gotthefunc))
        sendlog(gotthefunc, msg, 10)
        err = traceback.format_exc()
        msg = ('Unknown Error in {0} Detail: {1}'.format(gotthefunc,err))
        print(msg)
        sendlog(gotthefunc, msg, 10)
        sys.exit()
    try:
        sysinfo['SYSTEM']['HTTPPROXY'] = config.get('system', 'proxy')
    except (configparser.NoOptionError, configparser.InterpolationMissingOptionError):
        msg = ('No proxy specified in configuration file. Defaulting to none')
        sendlog(gotthefunc, msg, 10)
        pass
    except configparser.Error as e:
        msg = ('Config read entry system proxy error. Moving on.')
        sendlog(gotthefunc, msg, 10)
        pass
    except:
        msg = ('Error in {0} Reading Config! Moving on.'.format(gotthefunc))
        sendlog(gotthefunc, msg, 10)
        err = traceback.format_exc()
        msg = ('Error Detail: {0}'.format(err))
        sendlog(gotthefunc, msg, 10)
        pass
    else:
        msg = ('CONFIG: Got proxy {}'.format(sysinfo['SYSTEM']['HTTPPROXY']))
        sendlog(gotthefunc, msg, 10)
    try:
        sysinfo['SYSTEM']['HTTPTIMEOUT'] = int(config.get('system', 'httptimeout'))
    except (configparser.NoOptionError, configparser.InterpolationMissingOptionError):
        msg = ('No HTTPTIMEOUT specified in config. Defaulting to 60 seconds.')
        sendlog(gotthefunc, msg, 10)
        sysinfo['SYSTEM']['HTTPTIMEOUT'] = 60
        pass
    except configparser.Error as e:
        msg = ('No HTTPTIMEOUT specified in config. Defaulting to 60 seconds.')
        sendlog(gotthefunc, msg, 10)
        sysinfo['SYSTEM']['HTTPTIMEOUT'] = 60
        pass
    except:
        msg = ('Error in {0} Reading Config! Halting!'.format(gotthefunc))
        sendlog(gotthefunc, msg, 10)
        err = traceback.format_exc()
        msg = ('Error Detail: {0}'.format(err))
        sendlog(gotthefunc, msg, 10)
        sysinfo['SYSTEM']['HTTPTIMEOUT'] = 60
        msg = ('No HTTPTIMEOUT specified in config. Defaulting to 60 seconds.')
        sendlog(gotthefunc, msg, 10)
        pass
    else:
        msg = ('CONFIG: Got http timeout of {}'.format(sysinfo['SYSTEM']['HTTPTIMEOUT']))
        sendlog(gotthefunc, msg, 10)
    try:
        sysinfo['SYSTEM']['CONNECTION'] = config.get('system', 'connection')
    except (configparser.NoOptionError, configparser.InterpolationMissingOptionError):
        msg = ('No connection type (ip or serial) specified in configuration file. Defaulting to IP!')
        sendlog(gotthefunc, msg, 10)
        sysinfo['SYSTEM']['CONNECTION'] = 'ip'
        pass
    except configparser.Error as e:
        msg = ('Config read entry system connection error! Halting!')
        sendlog(gotthefunc, msg, 10)
        sys.exit()
    except:
        msg = ('Error in {0} Reading Config! Halting!'.format(gotthefunc))
        sendlog(gotthefunc, msg, 10)
        err = traceback.format_exc()
        msg = ('Error Detail: {0}'.format(err))
        sendlog(gotthefunc, msg, 10)
        sys.exit()
    else:
        msg = ('CONFIG: Got connection type {}'.format(sysinfo['SYSTEM']['CONNECTION']))
        sendlog(gotthefunc, msg, 10)
    if sysinfo['SYSTEM']['CONNECTION'] == 'ip':
        # Load display IP addresses from configuration
        IP = {}
        ipnum = 0
        for key, val in config.items('network'):
            if 'ip' in key:
                IP[ipnum]=val
                ipnum += 1
    elif sysinfo['SYSTEM']['CONNECTION'] == 'serial':
        try:
            sysinfo['SYSTEM']['SERIALPORT'] = config.get('serial', 'port')
        except (configparser.NoOptionError, configparser.InterpolationMissingOptionError):
            msg = ('No serial port specified in configuration file. Defaulting to /dev/ttyUSB0')
            sendlog(gotthefunc, msg, 10)
            sysinfo['SYSTEM']['SERIALPORT'] = '/dev/ttyUSB0'
            pass
        except configparser.Error as e:
            msg = ('Config read entry system serial port error! Halting!')
            sendlog(gotthefunc, msg, 10)

            sys.exit()
        except:
            msg = ('Error in {0} Reading Config! Halting!'.format(gotthefunc))
            sendlog(gotthefunc, msg, 10)
            err = traceback.format_exc()
            msg = ('Error Detail: {0}'.format(err))
            sendlog(gotthefunc, msg, 10)
            sys.exit()
    else:
        msg = ('Invalid connection type specified in configuration file. Halting!')
        sendlog(gotthefunc, msg, 10)
        sys.exit()
    try:
        sysinfo['SYSTEM']['MODE'] = config.get('system', 'mode')
    except (configparser.NoOptionError, configparser.InterpolationMissingOptionError):
        msg = ('No mode specified in configuration file. Defaulting to wall.')
        sendlog(gotthefunc, msg, 10)
        sysinfo['SYSTEM']['MODE'] = 'wall'
        pass
    except configparser.Error as e:
        msg = ('Config read entry system mode error. Moving on.')
        sendlog(gotthefunc, msg, 10)
        sysinfo['SYSTEM']['MODE'] = 'wall'
        pass
    except:
        msg = ('Error in {0} Reading Config! Moving on.'.format(gotthefunc))
        sendlog(gotthefunc, msg, 10)
        err = traceback.format_exc()
        msg = ('Error Detail: {0}'.format(err))
        sendlog(gotthefunc, msg, 10)
        sysinfo['SYSTEM']['MODE'] = 'wall'
        pass
    else:
        msg = ('CONFIG: Got mode {}'.format(sysinfo['SYSTEM']['MODE']))
        sendlog(gotthefunc, msg, 10)
    if sysinfo['SYSTEM']['MODE'] == 'wall':
        try:
            sysinfo['WALL']['NUMBERING'] = config.get('wall', 'numbering')
        except (configparser.NoOptionError, configparser.InterpolationMissingOptionError):
            msg = ('No numbering type specified in configuration file. Defaulting to zig-zag!')
            sendlog(gotthefunc, msg, 10)
            sysinfo['WALL']['NUMBERING'] = 'zig-zag'
            pass
        except configparser.Error as e:
            msg = ('Config read entry wall numbering error! Halting!')
            sendlog(gotthefunc, msg, 10)
            sys.exit()
        except:
            msg = ('Error in {0} Reading Config! Halting!'.format(gotthefunc))
            sendlog(gotthefunc, msg, 10)
            err = traceback.format_exc()
            msg = ('Error Detail: {0}'.format(err))
            sendlog(gotthefunc, msg, 10)
            sys.exit()
        try:
            sysinfo['WALL']['LAYOUT'] = config.get('wall', 'layout')
        except (configparser.NoOptionError, configparser.InterpolationMissingOptionError):
            msg = ('No video wall layout specified in configuration file. Halting!')
            sendlog(gotthefunc, msg, 10)
            sys.exit()
        except configparser.Error as e:
            msg = ('Config read entry wall layout error! Halting!')
            sendlog(gotthefunc, msg, 10)
            sys.exit()
        except:
            msg = ('Error in {0} Reading Config! Halting!'.format(gotthefunc))
            sendlog(gotthefunc, msg, 10)
            err = traceback.format_exc()
            msg = ('Error Detail: {0}'.format(err))
            sendlog(gotthefunc, msg, 10)
            sys.exit()
        try:
            sysinfo['SYSTEM']['DEFAULTINPUT'] = config.get('wall', 'defaultinput')
        except (configparser.NoOptionError, configparser.InterpolationMissingOptionError):
            msg = ('No default input specified in configuration file. Defaulting to DVI!')
            sendlog(gotthefunc, msg, 10)
            sysinfo['SYSTEM']['DEFAULTINPUT'] = 'dvi'
            pass
        except configparser.Error as e:
            msg = ('Config read entry wall defaultinput error! Halting!')
            sendlog(gotthefunc, msg, 10)
            sysinfo['SYSTEM']['DEFAULTINPUT'] = 'dvi'
            pass
        except:
            msg = ('Error in {0} Reading Config! Halting!'.format(gotthefunc))
            sendlog(gotthefunc, msg, 10)
            err = traceback.format_exc()
            msg = ('Error Detail: {0}'.format(err))
            sendlog(gotthefunc, msg, 10)
            sysinfo['SYSTEM']['DEFAULTINPUT'] = 'dvi'
            pass
        try:
            sysinfo['SYSTEM']['MATRIXIP'] = config.get('wall', 'matrixip')
        except (configparser.NoOptionError, configparser.InterpolationMissingOptionError):
            msg = ('No matrix switch ip address specified in configuration file. None will be applied to system.')
            sendlog(gotthefunc, msg, 10)
            sysinfo['SYSTEM']['MATRIXIP'] = None
            pass
        except configparser.Error as e:
            msg = ('Config read entry wall matrix ip error! Halting!')
            sendlog(gotthefunc, msg, 10)
            sys.exit()
        except:
            msg = ('Error in {0} Reading Config! Halting!'.format(gotthefunc))
            sendlog(gotthefunc, msg, 10)
            err = traceback.format_exc()
            msg = ('Error Detail: {0}'.format(err))
            sendlog(gotthefunc, msg, 10)
            sys.exit()
        else:
            msg = ('CONFIG: Retrieved matrix ip: {}'.format(sysinfo['SYSTEM']['MATRIXIP']))
            sendlog(gotthefunc, msg, 10)
        finally:
            sysinfo['SYSTEM']['USEMATRIX'] = 0
    
    if sysinfo['SYSTEM']['LOGLEVEL'] == '10':
        logger.setLevel(logging.DEBUG)
    if sysinfo['SYSTEM']['LOGLEVEL'] == '20':
        logger.setLevel(logging.INFO)
    if sysinfo['SYSTEM']['LOGLEVEL'] == '30':
        logger.setLevel(logging.WARNING)
    if sysinfo['SYSTEM']['LOGLEVEL'] == '40':
        logger.setLevel(logging.ERROR)
    if sysinfo['SYSTEM']['LOGLEVEL'] == '50':
        logger.setLevel(logging.CRITICAL)

    tsmain = time()
    
    if 'HTTPPROXY' in sysinfo['SYSTEM']:
        if len(sysinfo['SYSTEM']['HTTPPROXY']) > 0:
            os.environ["http_proxy"] = sysinfo['SYSTEM']['HTTPPROXY']
            os.environ["https_proxy"] = sysinfo['SYSTEM']['HTTPPROXY']
            
    msg = 'Gathering network information'
    sendlog(gotthefunc, msg, 10)
    gateways = {}
    msg = "Waiting for network to come up"

    sendlog(gotthefunc, msg, 10)
    while 'default' not in gateways or not defaultgateway:
        try:
            gateways = netifaces.gateways()
        except:
            pass
            msg = ("Exception in {}!:".format(gotthefunc))
            sendlog(gotthefunc, msg, 10)
            err = traceback.format_exc()
            msg = ('Error in {0} Detail: {1}'.format(gotthefunc,err))
            sendlog(gotthefunc, msg, 10)
        try:
            defaultgateway = gateways['default'][netifaces.AF_INET][0]
        except:
            pass
            defaultgateway = None
            msg = ('Network not ready in {0}.'.format(gotthefunc))
            sendlog(gotthefunc, msg, 10)
            sleep(1)
        else:
            msg = 'Obtained default gateway ip address'
            sendlog(gotthefunc, msg, 20)
    msg = 'Attempting to ping default gateway'
    sendlog(gotthefunc, msg, 10)
    while True:
        isup = ping(sysinfo, defaultgateway)
        if isup:
            msg = 'Default gateway {} is alive.'.format(defaultgateway)
            sendlog(gotthefunc, msg, 10)
            break
        else:
            msg = 'Default gateway {} is down. Looping.'.format(defaultgateway)
            sendlog(gotthefunc, msg, 10)
    if sysinfo['SYSTEM']['PLATFORM'].lower() == 'de':
            # Load license key
            try:
                sysinfo['SYSTEM']['LICENSEKEY'] = config.get('system', 'licensekey')
            except (configparser.NoOptionError, configparser.InterpolationMissingOptionError):
                msg = ('No license key in configuration file! Halting!')
                sendlog(gotthefunc, msg, 10)
                sys.exit()
            except configparser.Error as e:
                msg = ('Config read entry system license key error! Halting!')
                sendlog(gotthefunc, msg, 10)
                sys.exit()
            except:
                msg = ('Error in {0} Reading Config! Halting!'.format(gotthefunc))
                sendlog(gotthefunc, msg, 10)
                err = traceback.format_exc()
                msg = ('Error Detail: {0}'.format(err))
                sendlog(gotthefunc, msg, 10)
                sys.exit()
            else:
                msg = ('CONFIG: Loaded license key')
                sendlog(gotthefunc, msg, 10)            
    else:
        # Load token key
        try:
            sysinfo['SYSTEM']['TOKEN'] = config.get('system', 'token')
        except (configparser.NoOptionError, configparser.InterpolationMissingOptionError):
            err = traceback.format_exc()
            msg = ('Error in {0} Detail: {1}'.format(gotthefunc,err))
            sendlog(gotthefunc, msg, 10)
        except configparser.Error as e:
            err = traceback.format_exc()
            msg = ('Error in {0} Detail: {1}'.format(gotthefunc,err))
            sendlog(gotthefunc, msg, 10)        
        except:
            err = traceback.format_exc()
            msg = ('Error in {0} Detail: {1}'.format(gotthefunc,err))
            sendlog(gotthefunc, msg, 10)            
            sys.exit()
        if not sysinfo['SYSTEM']['TOKEN'] and sysinfo['SYSTEM']['PLATFORM'].lower() != 'de':
            looper = 0
            while looper < 5:
#                try:
#                    popup('LAVA Box Self-Provisioning','Please stand by.',3000)
#                except:
#                    err = traceback.format_exc()
#                    msg = ('Error in {} Detail: {}'.format(gotthefunc,err))
#                    sendlog(gotthefunc, msg, 10)
#                    pass
                try:
                    sysinfo['SYSTEM']['TOKEN'] = gettoken(sysinfo)
                except:
                    err = traceback.format_exc()
                    msg = ('Error in {0} Detail: {1}'.format(gotthefunc,err))
                    sendlog(gotthefunc, msg, 10)
                    subject = 'LAVA Box Failed Self-Provisioning'
                    message = 'LAVA Box Failed Self-Provisioning \n {}'.format(msg)
                    sendemail(sysinfo,subject,message)
                    sleep(5)
                else:
                    break
                looper += 1
            if looper >= 5:
                msg = ('LAVA Box Failed Self-Provisioning Please contact support@lavacontrols.com!')
                sendlog(gotthefunc, msg, 10)  
#                try:
#                    popup('LAVA Box Failed Self-Provisioning','Please contact support@lavacontrols.com!',3000000)
#                except:
#                    err = traceback.format_exc()
#                    msg = ('Error in {} Detail: {}'.format(gotthefunc,err))
#                    sendlog(gotthefunc, msg, 10)
#                    pass
#                else:
#                    sleep(300)
#                    sys.exit()
            else:
                configbuilder(sysinfo['SYSTEM']['LAVACONTROLSCONFIGFILE'], token=sysinfo['SYSTEM']['TOKEN'])

    # Test network connection
    
    
    
    
        
    if sysinfo['SYSTEM']['CONNECTION'] == 'ip':
        try:
            walldown = iswallalive(sysinfo, IP)
        except:
            msg = ('Error in {0}!'.format(gotthefunc))
            sendlog(gotthefunc, msg, 10)  
            err = traceback.format_exc()
            msg = ('Error in {0} Detail: {1}'.format(gotthefunc,err))
            sendlog(gotthefunc, msg, 10)
            sys.exit()
        if walldown == 1:
            msg = ('One or more wall displays are unreachable. Halting system. Add self-healing stuff here.'.format(gotthefunc,err))
            sendlog(gotthefunc, msg, 10)  

##### Borrowed from declientlib. Added as placeholder. Function copied to lavacontrolslib but needs to be converted to lavacontrols.            
#            tempjobsdata['SYSTEM']['EMAIL'] = ['sloeckle@lucidnetworks.net']
#            sendemail(tempjobsdata,subject,message)


        # Begin startupdisplaystatus to query all displays for current configuration and status.
        # Additionally, ID to IP learning and mapping takes place.

        socketnum = 0
        startupqueue = Queue()
        startupworkers = []
        for ipid, ipaddr in IP.items():
            now = datetime.datetime.now()
            startupworker = Process(target=startupdisplaystatus, args=(sysinfo, ipaddr, socketnum, startupqueue))
            startupworkers.append(startupworker)
            startupworker.start()
            socketnum += 1
        sysinfo['SYSTEM']['DISPLAYS'] = socketnum
        startupresults = {}
        for i in range(socketnum):
            startupqueuedata = startupqueue.get()
            sendlog(gotthefunc, startupqueuedata, 10)
            update_dict(startupresults, startupqueuedata)
        for w in startupworkers:
            w.join()
        sortedresults = collections.OrderedDict(sorted(startupresults.items()))
        
    if sysinfo['SYSTEM']['CONNECTION'] == 'serial':
        
        if sysinfo['SYSTEM']['MODE'] == 'single':
            startupresults = startupdisplaystatus(sysinfo)
        elif sysinfo['SYSTEM']['MODE'] == 'wall':
            layout = sysinfo['WALL']['LAYOUT'].split('x')
            displaycount = int(int(layout[0])+int(layout[1]))
            x = 1
            y = 0
            startupresults = {}
            while x < displaycount:
                startupresult = startupdisplaystatus(sysinfo, socketid=y, id=x)
                update_dict(startupresults, startupresult)
                x += 1
                y += 1
        sortedresults = collections.OrderedDict(sorted(startupresults.items()))
        
    for key,val in sortedresults.items():
        val['LAVA_ID'] = 'UNKNOWN'
        try:
            if not val['F1']:
                val['F1'] = ''
        except:
            pass
            val['F1'] = ''
        try:
            if not val['F2']:
                val['F2'] = ''
        except:
            pass
            val['F2'] = ''
        try:
            if not val['F3']:
                val['F3'] = ''
        except:
            pass
            val['F3'] = ''
        try:
            if not val['F4']:
                val['F4'] = ''
        except:
            pass
            val['F4'] = ''
        try:
            if not val['LAVA_ID']:
                val['LAVA_ID'] = ''
        except:
            pass
            val['LAVA_ID'] = ''
        dbsuccess = 0
        
        while dbsuccess == 0:
            try:
                conn = sqlite3.connect(sysinfo['SYSTEM']['DATABASEFILE'])
                c = conn.cursor()
                c.execute('SELECT id, lava_id FROM displays WHERE serial = ?', (val['SERIAL'],))
            except sqlite3.OperationalError:
                pass
                msg = ('{}: Database locked (27). Trying again.',format(gotthefunc))
                sendlog(gotthefunc, msg, 10)
                sleep(0.5)
            except:
                pass
                err = traceback.format_exc()
                msg = ('Error in {0} Detail: {1}'.format(gotthefunc,err))
                sendlog(gotthefunc, msg, 10)
                sleep(0.5)
            else:
                row = c.fetchone()
                dbsuccess = 1
            finally:
                conn.close()
        if sysinfo['SYSTEM']['PLATFORM'].lower() != 'de':
            try:
                apiqueryconn = QueryAPI(sysinfo)
            except:
                pass
                err = traceback.format_exc()
                msg = ('Error in {} Detail: {}'.format(gotthefunc,err))
                sendlog(gotthefunc, msg, 10)      
            while True:        
                try:
                    displayinfo = apiqueryconn.display(val['ID'])
                except:
                    pass
                    err = traceback.format_exc()
                    msg = ('Error in {} Detail: {}'.format(gotthefunc,err))
                    sendlog(gotthefunc, msg, 10)     
                    msg = ("Data retreived from apiqueryconn.display(val['ID']): {}".format(displayinfo))
                    sendlog(gotthefunc, msg, 10)     
                else:
                    break
            try:
                val['LAVA_ID'] = displayinfo['id']
            except:
                msg = ('No displays configured in LAVA API. Halting.')
                sendlog(gotthefunc, msg, 10)     
                err = traceback.format_exc()
                msg = ('Error in {} Detail: {}'.format(gotthefunc,err))
                sendlog(gotthefunc, msg, 10)        
                sys.exit()
        if row is None:
            try:
                if sysinfo['SYSTEM']['MODE'] == 'wall':
                    dbsuccess = 0
                    while dbsuccess == 0:
                        try:
                            conn = sqlite3.connect(sysinfo['SYSTEM']['DATABASEFILE'])
                            c = conn.cursor()
                            c.execute('INSERT into displays (model, serial, ip, make, f1, f2, f3, f4, id, lava_id, power_state, input, volume, tile_state, tile_h, tile_v, tile_p) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)', (val['MODEL'], val['SERIAL'], val['IP'], val['MAKE'], val['F1'], val['F2'], val['F3'], val['F4'], val['ID'], val['LAVA_ID'], val['PWR'], val['INPUT'], val['VOL'], val['TMMODE'], val['TMH'], val['TMV'], val['TMP']))
                            conn.commit()
                        except sqlite3.OperationalError:
                            pass
                            msg = ('{}: Database locked (28). Trying again.',format(gotthefunc))
                            sendlog(gotthefunc, msg, 10)
                            sleep(0.5)
                        except:
                            pass
                            err = traceback.format_exc()
                            msg = ('Error in {0} Detail: {1}'.format(gotthefunc,err))
                            sendlog(gotthefunc, msg, 10)
                            sleep(0.5)
                        else:
                            dbsuccess = 1
                        finally:
                            conn.close()
                else:
                    dbsuccess = 0
                    while dbsuccess == 0:
                        try:
                            conn = sqlite3.connect(sysinfo['SYSTEM']['DATABASEFILE'])
                            c = conn.cursor()
                            c.execute('INSERT into displays (model, serial, ip, make, f1, f2, f3, f4, id, lava_id, power_state, input, volume) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)', (val['MODEL'], val['SERIAL'], val['IP'], val['MAKE'], val['F1'], val['F2'], val['F3'], val['F4'], val['ID'], val['LAVA_ID'], val['PWR'], val['INPUT'], val['VOL']))
                            conn.commit()
                        except sqlite3.OperationalError:
                            pass
                            msg = ('{}: Database locked (29). Trying again.',format(gotthefunc))
                            sendlog(gotthefunc, msg, 10)
                            sleep(0.5)
                        except:
                            pass
                            err = traceback.format_exc()
                            msg = ('Error in {0} Detail: {1}'.format(gotthefunc,err))
                            sendlog(gotthefunc, msg, 10)
                            sleep(0.5)
                        else:
                            dbsuccess = 1
                        finally:
                            conn.close()
            except:
                msg = ('Startup display entry insert for {} failed. Pass.'.format(key))
                sendlog(gotthefunc, msg, 10)     
                err = traceback.format_exc()
                msg = ('Error Detail: {0}'.format(err))
                sendlog(gotthefunc, msg, 10)       
                pass
                sleep(0.5)
            else:
                msg = ('Startup display entry insert for {} successful.'.format(key))
                sendlog(gotthefunc, msg, 10)     
                dbsuccess = 1
        else:
            try:
                if sysinfo['SYSTEM']['MODE'] == 'wall':          
                    dbsuccess = 0
                    while dbsuccess == 0:
                        try:
                            conn = sqlite3.connect(sysinfo['SYSTEM']['DATABASEFILE'])
                            c = conn.cursor()     
                            c.execute('UPDATE displays SET ip = ?, make = ?, f1 = ?, f2 = ?, f3 = ?, f4 = ?, id = ?, lava_id = ?, power_state = ?, input = ?, volume = ?, tile_state = ?, tile_h = ?, tile_v = ?, tile_p = ? WHERE serial = ?', (val['IP'], val['MAKE'], val['F1'], val['F2'], val['F3'], val['F4'], val['ID'], val['LAVA_ID'], val['PWR'], val['INPUT'], val['VOL'], val['TMMODE'], val['TMH'], val['TMV'], val['TMP'], val['SERIAL']))
                            conn.commit()
                        except sqlite3.OperationalError:
                            pass
                            msg = ('{}: Database locked (30). Trying again.',format(gotthefunc))
                            sendlog(gotthefunc, msg, 10)
                            sleep(0.5)
                        except:
                            pass
                            err = traceback.format_exc()
                            msg = ('Error in {0} Detail: {1}'.format(gotthefunc,err))
                            sendlog(gotthefunc, msg, 10)
                            sleep(0.5)
                        else:
                            dbsuccess = 1
                        finally:
                            conn.close()
                else:
                    dbsuccess = 0
                    while dbsuccess == 0:
                        try:
                            conn = sqlite3.connect(sysinfo['SYSTEM']['DATABASEFILE'])
                            c = conn.cursor()     
                            c.execute('UPDATE displays SET ip = ?, make = ?, f1 = ?, f2 = ?, f3 = ?, f4 = ?, id = ?, lava_id = ?, power_state = ?, input = ?, volume = ? WHERE serial = ?', (val['IP'], val['MAKE'], val['F1'], val['F2'], val['F3'], val['F4'], val['ID'], val['LAVA_ID'], val['PWR'], val['INPUT'], val['VOL'], val['SERIAL']))
                            conn.commit()
                        except sqlite3.OperationalError:
                            pass
                            msg = ('{}: Database locked (31). Trying again.',format(gotthefunc))
                            sendlog(gotthefunc, msg, 10)
                            sleep(0.5)
                        except:
                            pass
                            err = traceback.format_exc()
                            msg = ('Error in {0} Detail: {1}'.format(gotthefunc,err))
                            sendlog(gotthefunc, msg, 10)
                            sleep(0.5)
                        else:
                            dbsuccess = 1
                        finally:
                            conn.close()
            except:
                err = traceback.format_exc()
                sendlog(gotthefunc, msg, 10)     
                pass
                sleep(0.5)
            else:
                msg = ('Startup display entry update for {} successful.'.format(key))
                sendlog(gotthefunc, msg, 10)     
            startupresults['D{0}'.format(row[0])]['lava_id'] = row[1]
    update_dict(sysinfo, startupresults)

    msg = ('Took {}'.format(time() - tsmain))
    sendlog(gotthefunc, msg, 10)     
    # Merge startup results into master sysinfo dictionary
    
    # Let's set some display defaults, like OSD Off

    if sysinfo['SYSTEM']['CONNECTION'] == 'ip':
        tsmain = time()
        socketnum = 0
        setdefaultqueue = Queue()
        setdefaultworkers = []
        for key, value in sysinfo.items():
            if key.startswith('D') and key != 'DNone':
                setdefaultworker = Process(target=setdefaults, args=(sysinfo, sysinfo['{}'.format(key)]['ID'], socketnum, setdefaultqueue))
                setdefaultworkers.append(setdefaultworker)
                setdefaultworker.start()
                socketnum += 1
        setdefaultresults = {}
        for i in range(socketnum):
            update_dict(setdefaultresults, setdefaultqueue.get())
        for w in setdefaultworkers:
            w.join()
    elif sysinfo['SYSTEM']['CONNECTION'] == 'serial':
        if sysinfo['SYSTEM']['MODE'] == 'single':
            setdefaultresults = {}
            for key, value in sysinfo.items():
                if key.startswith('D') and key != 'DNone':
                    setdefaultresult = setdefaults(sysinfo, sysinfo['{}'.format(key)]['ID'])
                    update_dict(setdefaultresults, setdefaultresult)
        elif sysinfo['SYSTEM']['MODE'] == 'wall':
            setdefaultresults = {}
            for key, value in sysinfo.items():
                if key.startswith('D') and key != 'DNone':
                    setdefaultresult = setdefaults(sysinfo, sysinfo['{}'.format(key)]['ID'])
                    update_dict(setdefaultresults, setdefaultresult)
    sortedresults = collections.OrderedDict(sorted(setdefaultresults.items()))
    for key,val in sortedresults.items():
        msg = ("{0} = {1}".format(key,val))
        sendlog(gotthefunc, msg, 10)     
        dbsuccess = 0
        while dbsuccess == 0:
            try:
                conn = sqlite3.connect(sysinfo['SYSTEM']['DATABASEFILE'])
                c = conn.cursor()
                c.execute('SELECT * FROM displays WHERE serial = ?', (val['SERIAL'],))
            except sqlite3.OperationalError:
                pass
                msg = ('{}: Database locked (32). Trying again.',format(gotthefunc))
                sendlog(gotthefunc, msg, 10)
                sleep(0.5)
            except:
                pass
                err = traceback.format_exc()
                msg = ('Error in {0} Detail: {1}'.format(gotthefunc,err))
                sendlog(gotthefunc, msg, 10)
                sleep(0.5)
            else:
                row = c.fetchone()
                dbsuccess = 1
            finally:
                conn.close()
        if row is None:
            msg = ('{} Display with serial {} does not exist in database. Something is wrong.'.format(key,val['SERIAL']))
            sendlog(gotthefunc, msg, 10)     
        else:
            msg = ('{} Display with serial {} found in database. Updating.'.format(key,val['SERIAL']))
            sendlog(gotthefunc, msg, 10)     
            dbsuccess = 0
            while dbsuccess == 0:
                try:
                    conn = sqlite3.connect(sysinfo['SYSTEM']['DATABASEFILE'])
                    c = conn.cursor()
                    c.execute('UPDATE displays SET osd = ? WHERE serial = ?', (val['OSD'], val['SERIAL']))
                    conn.commit()
                except sqlite3.OperationalError:
                    pass
                    msg = ('{}: Database locked (33). Trying again.',format(gotthefunc))
                    sendlog(gotthefunc, msg, 10)
                    sleep(0.5)
                except:
                    pass
                    err = traceback.format_exc()
                    msg = ('Error in {0} Detail: {1}'.format(gotthefunc,err))
                    sendlog(gotthefunc, msg, 10)
                    sleep(0.5)
                else:
                    conn.close()
                finally:
                    dbsuccess = 1
    msg = ('Took {}'.format(time() - tsmain))
    sendlog(gotthefunc, msg, 10)            
    update_dict(sysinfo, setdefaultresults)

    # If it exists, load old state file in case there was a power issue
    defaultsystem = 0
    laststate = {}
    sysinfo['SYSTEM']['LASTUPDATED'] = 0
    sysinfo['SYSTEM']['COMMAND'] = None
    sysinfo['SYSTEM']['TILE'] = 0
    sysinfo['SYSTEM']['BASEINPUT'] = None
    sysinfo['SYSTEM']['CHAIN']['ON'] = 0
    
        # Set LASTINPUT to default input from config if LASTINPUT has never been set

    # Begin cloud server query for data
    test = 0
    mainworker = Process(target=api, args=(sysinfo,))
    mainworkers.append(mainworker)
    mainworker.start()
    mainworker = Process(target=hardware, args=(sysinfo,test))
    mainworkers.append(mainworker)
    mainworker.start()
    mainworker = Process(target=jobs, args=(sysinfo,test))
    mainworkers.append(mainworker)
    mainworker.start()
    for w in mainworkers:
        w.join()
        
    msg = ('Exited {} function'.format(gotthefunc))
    sendlog(gotthefunc, msg, 10)
#    logworker.join()


if __name__ == '__main__':
    freeze_support()
    if osplatform == 'windows':
        application_path = os.getcwd()
        lockfile = ('{}\\db\\lavacontrols.run'.format(application_path))
        try:
            lock = zc.lockfile.LockFile(lockfile, content_template='{pid};{hostname}')
        except:
            sys.exit()
    main()