#!/usr/bin/python3
# Cloud Display Control - Copyright 2018 Lucid Networks - Stephen Loeckle

import socket
import serial
import binascii
import logging
import socketserver
import struct
import os
import sys
import time
import json
import inspect
from time import time, sleep
import datetime
import collections
import configparser
import argparse
import pickle
import urllib.request
import traceback
import netifaces
import subprocess
from multiprocessing import Process, Queue
from cdclib import buildtm, dict_diff, fetchcmd, getinput, getfirmware, getmac, getmodel, getpowermode, getserial, gettmmode, gettmpos, getvolume, sendlog, saveconfig, savestate, sendemail, sethdmimodes, setinput, setmatrixroute, setosd, setpower, settm, setvolume, sockclose, Timeout, update_dict, waitfornetwork

PORT = 7142

class LogRecordStreamHandler(socketserver.StreamRequestHandler):
    def handle(self):
        while True:
            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)

    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

    def __init__(self, host='localhost',
                 port=logging.handlers.DEFAULT_TCP_LOGGING_PORT,
                 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:
            rd, wr, ex = select.select([self.socket.fileno()],
                                       [], [],
                                       self.timeout)
            if rd:
                self.handle_request()
            abort = self.abort
            
def pingold(ip=None, socketid=0, q=None):
    gotthefunc = inspect.stack()[0][3]
    msg = ('Entered {} function'.format(gotthefunc))
    sendlog(gotthefunc, msg, 10)
    ts = time()
    s = {}
    output = {}
    output['{0}'.format(ip)] = {}
    try:
        p = subprocess.Popen(['ping',ip,'-c','1','-W','2'])
    except:
        pass
        msg = ("Exception in {}!:".format(gotthefunc))
        sendlog(gotthefunc, msg, 40)
        err = traceback.format_exc()
        msg = ('Unknown Error in {0} Detail: {1}'.format(gotthefunc,err))
        sendlog(gotthefunc, msg, 10)
        print(msg)
        output['{0}'.format(ip)]['UP'] = False
        return(output)
    p.wait()
    if not p.poll():
        output['{0}'.format(ip)]['UP'] = True
        up = 1
    else:
        output['{0}'.format(ip)]['UP'] = False
        up = 0
    if q:
        q.put(output)
        msg = ('Exited {} function'.format(gotthefunc))
        sendlog(gotthefunc, msg, 10)
    else:
        msg = ('Exited {} function'.format(gotthefunc))
        sendlog(gotthefunc, msg, 10)
        return(output)
        
def ping(host=None, socketid=0, q=None):
    gotthefunc = inspect.stack()[0][3]
    msg = ('Entered {} function'.format(gotthefunc))
    sendlog(gotthefunc, msg, 10)
    ts = time()
    s = {}
    output = {}
    output['{0}'.format(host)] = {}
    msg = 'Beginning ping {}'.format(host)
    sendlog(gotthefunc, msg, 10)
    try:
        p = subprocess.call(['ping', '-c', '1', '-W', '2', host], stdout=open(os.devnull, 'w'), stderr=open(os.devnull, 'w'))
    except:
        pass
        msg = ("Exception in {}!:".format(gotthefunc))
        sendlog(gotthefunc, msg, 40)
        err = traceback.format_exc()
        msg = ('Unknown Error in {0} Detail: {1}'.format(gotthefunc,err))
        sendlog(gotthefunc, msg, 10)
        print(msg)
        output['{0}'.format(host)]['UP'] = False
        return(output)
    msg = 'Ping complete. Testing results.'
    sendlog(gotthefunc, msg, 10)
    if p == 0:
        output['{0}'.format(host)]['UP'] = True
        up = 1
    else:
        output['{0}'.format(host)]['UP'] = False
        up = 0
    if q:
        q.put(output)
        msg = ('Exited {} function'.format(gotthefunc))
        sendlog(gotthefunc, msg, 10)
    else:
        msg = ('Exited {} function'.format(gotthefunc))
        sendlog(gotthefunc, msg, 10)
        return(output)
        

def startupdisplaystatus(connection, ip=None, port=None, socketid=0, q=None, serial=None):
    gotthefunc = inspect.stack()[0][3]
    msg = ('Entered {} function'.format(gotthefunc))
    sendlog(gotthefunc, msg, 10)
    ts = time()
    s = {}
    if connection == 'ip':
        s[socketid] = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        s[socketid].settimeout(10)
        s[socketid].connect((ip, port))
        s[socketid].send(b"\x01\x30\x2A\x30\x43\x30\x36\x02\x30\x32\x33\x45\x03\x1A\x0D")
        response = s[socketid].recv(27)
    elif connection == 'serial':
        s[socketid] = serial
        s[socketid].write(b"\x01\x30\x2A\x30\x43\x30\x36\x02\x30\x32\x33\x45\x03\x1A\x0D")
        s[socketid].flushInput()
        response = s[socketid].read(27)
    hexresponse = binascii.b2a_hex(response)
    if hexresponse == b'01303041443132023030303233453030303036343030303103700d':
        displayid = 1
    if hexresponse == b'01303042443132023030303233453030303036343030303203700d':
        displayid = 2
    if hexresponse == b'01303043443132023030303233453030303036343030303303700d':
        displayid = 3
    if hexresponse == b'01303044443132023030303233453030303036343030303403700d':
        displayid = 4
    if hexresponse == b'01303045443132023030303233453030303036343030303503700d':
        displayid = 5
    if hexresponse == b'01303046443132023030303233453030303036343030303603700d':
        displayid = 6
    if hexresponse == b'01303047443132023030303233453030303036343030303703700d':
        displayid = 7
    if hexresponse == b'01303048443132023030303233453030303036343030303803700d':
        displayid = 8
    if hexresponse == b'01303049443132023030303233453030303036343030303903700d':
        displayid = 9
    if hexresponse == b'0130304a4431320230303032334530303030363430303041030b0d':
        displayid = 10

    output = {}
    output['D{0}'.format(displayid)] = {}
    output['D{0}'.format(displayid)]['IP'] = ip
    output['D{0}'.format(displayid)]['ID'] = displayid
    output['D{0}'.format(displayid)]['MODEL'] = getmodel(displayid,s[socketid])
    output['D{0}'.format(displayid)]['SERIAL'] = getserial(displayid,s[socketid])
    output['D{0}'.format(displayid)]['F1'],output['D{0}'.format(displayid)]['F2'],output['D{0}'.format(displayid)]['F3'],output['D{0}'.format(displayid)]['F4'] = getfirmware(displayid,s[socketid])
    output['D{0}'.format(displayid)]['INPUT'] = getinput(displayid,s[socketid])
    output['D{0}'.format(displayid)]['TMMODE'] = gettmmode(displayid,s[socketid])
    output['D{0}'.format(displayid)]['TMBC'] = gettmpos(displayid,s[socketid])
    output['D{0}'.format(displayid)]['TMH'] = gettmpos(displayid,s[socketid])
    output['D{0}'.format(displayid)]['TMV'] = gettmpos(displayid,s[socketid])
    output['D{0}'.format(displayid)]['TMP'] = gettmpos(displayid,s[socketid])
    output['D{0}'.format(displayid)]['PWR'] = getpowermode(displayid,s[socketid])
    output['D{0}'.format(displayid)]['VOL'] = getvolume(displayid,s[socketid])
    sockclose(s[socketid],gotthefunc)
    output['D{0}'.format(displayid)]['ST'] = 'Last process time: {0}'.format(time() - ts)
    q.put(output)
    msg = ('Exited {} function'.format(gotthefunc))
    sendlog(gotthefunc, msg, 10)

def setdefaults(ip, port, displaynum, socketid, q):
    gotthefunc = inspect.stack()[0][3]
    msg = ('Entered {} function with options {}'.format(gotthefunc, displaynum))
    sendlog(gotthefunc, msg, 10)
    ts = time()
    s = {}
    s[socketid] = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s[socketid].settimeout(10)
    s[socketid].connect((ip, port))
    output = {}
    output['D{0}'.format(displaynum)] = {}
    output['D{0}'.format(displaynum)]['OSD'] = setosd(displaynum,0,s[socketid])
    sockclose(s[socketid],gotthefunc)
    output['D{0}'.format(displaynum)]['FUNCNAME'] = gotthefunc
    output['D{0}'.format(displaynum)]['FUNCTIME'] = 'Last process time: {0}'.format(time() - ts)
    q.put(output)
    msg = ('Exited {} function'.format(gotthefunc))
    sendlog(gotthefunc, msg, 10)

def buildtmworker(sysinfo, port, displaynum, hnum, vnum, pos, socketid, q):
    gotthefunc = inspect.stack()[0][3]
    msg = ('Entered {} function with options {} {} {} {}'.format(gotthefunc,displaynum, hnum, vnum, pos))
    sendlog(gotthefunc, msg, 10)
    ts = time()
    output = {} 
    output['D{0}'.format(displaynum)] = {}
    target = sysinfo['SYSTEM']['TARGET']
    s = {}
    s[socketid] = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s[socketid].settimeout(10)
    s[socketid].connect((sysinfo['D{}'.format(displaynum)]['IP'], port))
#    returnbcmode, returnhnum, returnvnum, returnpos = buildtm(target,displaynum,hnum,vnum,pos,sysinfo['WALL']['WIRING'],s[socketid])
    if displaynum != sysinfo['SYSTEM']['TARGET']:
        if sysinfo['SYSTEM']['DPCHAIN'] == 1:
            if sysinfo['D{0}'.format(displaynum)]['TMMODE'] == 0:
               output['D{0}'.format(displaynum)]['LASTINPUT'] = sysinfo['D{0}'.format(displaynum)]['INPUT']
            returninput = setinput(displaynum, 'dp', sysinfo['WALL']['MODEL'], s[socketid])
            msg = returninput
            sendlog(gotthefunc, msg, 10)
            output['D{0}'.format(displaynum)]['INPUT'] = returninput
        else:
            msg = 'D{0}: DP Chain Disabled'.format(displaynum)
            sendlog(gotthefunc, msg, 10)
    else:
        msg = ('displaynum from builttmworker = {}'.format(displaynum))
        sendlog(gotthefunc, msg, 10)
    returnbcmode, returnhnum, returnvnum, returnpos = buildtm(target,displaynum,hnum,vnum,pos,sysinfo['WALL']['WIRING'],s[socketid])
    returntmmode = settm(displaynum, 1, s[socketid])
    output['D{0}'.format(displaynum)]['SAVED']=0
    returnsaved = saveconfig(displaynum, s[socketid])
    output['D{0}'.format(displaynum)]['TMMODE']=returntmmode
    output['D{0}'.format(displaynum)]['TMBC']=returnbcmode
    output['D{0}'.format(displaynum)]['TMH']=returnhnum
    output['D{0}'.format(displaynum)]['TMV']=returnvnum
    output['D{0}'.format(displaynum)]['TMP']=returnpos
    output['D{0}'.format(displaynum)]['SAVED']=returnsaved
    output['D{0}'.format(displaynum)]['TILED']=1
    sockclose(s[socketid],gotthefunc)
    output['D{0}'.format(displaynum)]['TMTIME'] = 'Last process time: {0}'.format(time() - ts)
    q.put(output)
    msg = ('Exited {} function'.format(gotthefunc))
    sendlog(gotthefunc, msg, 10)

def buildtmwork(sysinfo,h,w):
    gotthefunc = inspect.stack()[0][3]
    msg = ('Entered {} function'.format(gotthefunc))
    sendlog(gotthefunc, msg, 10)
    tsmain = time()
    socketnum = 0
    target = sysinfo['SYSTEM']['TARGET']
    displaynum = sysinfo['SYSTEM']['TARGET']
    end = displaynum + (h*w)
    position = 1
    buildtmq = Queue()
    buildtmqresults = {}
    buildtmprocs = []
    while (displaynum < end):
        buildtmproc = Process(target=buildtmworker, args=(sysinfo, PORT, displaynum, h, w, position, socketnum, buildtmq))
        buildtmprocs.append(buildtmproc)
        socketnum += 1
        displaynum += 1
        position += 1
    if sysinfo['SYSTEM']['USEMATRIX'] == 1:
#        setmatrixroute(sysinfo['SYSTEM']['MATRIXIP'],sysinfo['SYSTEM']['MYIP'],sysinfo['SYSTEM']['MATRIXCOMMANDS'])
        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)
    print('*********************************************************************************************')
    print(buildtmqresults)
    print('*********************************************************************************************')
    return(buildtmqresults)
    
def buildtm2x2(sysinfo):
    gotthefunc = inspect.stack()[0][3]
    msg = ('Entered {} function'.format(gotthefunc))
    sendlog(gotthefunc, msg, 10)
    tsmain = time()
    socketnum = 0
    target = sysinfo['SYSTEM']['TARGET']
    displaynum = sysinfo['SYSTEM']['TARGET']
    end = displaynum + 4
    position = 1
    buildtm2x2q = Queue()
    buildtm2x2qresults = {}
    buildtm2x2workers = []
    while (displaynum < end):
       buildtm2x2worker = Process(target=buildtmworker, args=(sysinfo, PORT, displaynum, 2, 2, position, socketnum, buildtm2x2q))
       buildtm2x2workers.append(buildtm2x2worker)
       socketnum += 1
       displaynum += 1
       position += 1
    for w in buildtm2x2workers:
        w.start()
    for i in range(socketnum):
        update_dict(buildtm2x2qresults, buildtm2x2q.get())
    for w in buildtm2x2workers:
        w.join()
    msg = ('Took {}'.format(time() - tsmain))
    sendlog(gotthefunc, msg, 10)
    msg = buildtm2x2qresults
    sendlog(gotthefunc, msg, 10)
    msg = ('Exited {} function'.format(gotthefunc))
    sendlog(gotthefunc, msg, 10)
    print('*********************************************************************************************')
    print(buildtm2x2qresults)
    print('*********************************************************************************************')
    return(buildtm2x2qresults)
    
def buildtm3x3(sysinfo):
    gotthefunc = inspect.stack()[0][3]
    msg = ('Entered {} function'.format(gotthefunc))
    sendlog(gotthefunc, msg, 10)
    tsmain = time()
    socketnum = 0
    target = sysinfo['SYSTEM']['TARGET']
    displaynum = sysinfo['SYSTEM']['TARGET']
    end = displaynum + 9
    position = 1
    buildtm3x3q = Queue()
    buildtm3x3qresults = {}
    buildtm3x3workers = []
    while (displaynum < end):
       buildtm3x3worker = Process(target=buildtmworker, args=(sysinfo, PORT, displaynum, 3, 3, position, socketnum, buildtm3x3q))
       buildtm3x3workers.append(buildtm3x3worker)
       socketnum += 1
       displaynum += 1
       position += 1
    for w in buildtm3x3workers:
        w.start()
    for i in range(socketnum):
        update_dict(buildtm3x3qresults, buildtm3x3q.get())
    for w in buildtm3x3workers:
        w.join()
    msg = ('Took {}'.format(time() - tsmain))
    sendlog(gotthefunc, msg, 10)
    msg = buildtm3x3qresults
    sendlog(gotthefunc, msg, 10)
    msg = ('Exited {} function'.format(gotthefunc))
    sendlog(gotthefunc, msg, 10)
    return(buildtm3x3qresults)

def changeinput(sysinfo, input, displaynum=999):
    gotthefunc = inspect.stack()[0][3]
    wallmodel = sysinfo['WALL']['MODEL']
    ip = sysinfo['D{0}'.format(sysinfo['SYSTEM']['TARGET'])]['IP']
    msg = ('Entered {} function with options {} {} {}'.format(gotthefunc, displaynum, input, wallmodel))
    sendlog(gotthefunc, msg, 10)
    if displaynum == 999:
        displaynum = sysinfo['SYSTEM']['TARGET']
        msg = ('CHANGEINPUT: Fetching displaynum from sysinfo target: {}'.format(displaynum))
        sendlog(gotthefunc, msg, 10)
    else:
        ip = sysinfo['D{0}'.format(displaynum)]['IP']
        msg = ('CHANGEINPUT: Fetching displaynum from arguments passed to function: {}'.format(displaynum))
        sendlog(gotthefunc, msg, 10)
    ts = time()
    output = {}
    output['D{0}'.format(displaynum)] = {}
    output['D{0}'.format(displaynum)]['LASTINPUT'] = sysinfo['D{0}'.format(displaynum)]['INPUT']
    s = {}
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.settimeout(10)
    s.connect((ip, PORT))
    returninputstatus = setinput(displaynum, input, wallmodel, s)
##  Need to store hdmi mode (or any other input) states
    if input == 'hdmi':
        returninputsettings = sethdmimodes(displaynum, s)
    output['D{0}'.format(displaynum)]['SAVED']=0
    returnsaved = saveconfig(displaynum, s)
    output['D{0}'.format(displaynum)]['SAVED']=returnsaved
    output['D{0}'.format(displaynum)]['INPUT']=returninputstatus
    sockclose(s,gotthefunc)
    output['D{0}'.format(displaynum)]['CHANGEINPUTTIME'] = 'Last process time: {0}'.format(time() - ts)
    msg = ('Exited {} function'.format(gotthefunc))
    sendlog(gotthefunc, msg, 10)
    return(output)
    

def changeinputprocess(ip, port, displaynum, input, lastinput, wallmodel, socketid, q):
    gotthefunc = inspect.stack()[0][3]
    msg = ('Entered {} function with options {} {} {} {}'.format(gotthefunc, displaynum, input, lastinput, wallmodel))
    sendlog(gotthefunc, msg, 10)
    ts = time()
    output = {}
    output['D{0}'.format(displaynum)] = {}
    s = {}
    s[socketid] = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s[socketid].settimeout(10)
    s[socketid].connect((ip, port))
    returninputstatus = setinput(displaynum, input, wallmodel, s[socketid])
    if input == 'hdmi':
        returninputsettings = sethdmimodes(displaynum, s[socketid])
    output['D{0}'.format(displaynum)]['SAVED']=0
    returnsaved = saveconfig(displaynum, s[socketid])
    output['D{0}'.format(displaynum)]['SAVED']=returnsaved
    output['D{0}'.format(displaynum)]['INPUT']=returninputstatus
    sockclose(s[socketid],gotthefunc)
    output['D{0}'.format(displaynum)]['CHANGEINPUTTIME'] = 'Last process time: {0}'.format(time() - ts)
    # I put the lastinput variable set here, as opposed to changeinputall master function because I don't want it changed unless the new input change was successful
    output['D{0}'.format(displaynum)]['LASTINPUT'] = lastinput
    q.put(output)
    msg = ('Exited {} function'.format(gotthefunc))
    sendlog(gotthefunc, msg, 10)

def changeinputall(sysinfo, input):
    gotthefunc = inspect.stack()[0][3]
    msg = ('Entered {} function with options {}'.format(gotthefunc, input))
    sendlog(gotthefunc, msg, 10)
    tsmain = time()
    socketnum = 0
    dpchain = 0
    changeinputallqueue = Queue()
    changeinputallqueueresults = {}
    changeinputallworkers = []
    for key, value in sysinfo.items():
        if key.startswith('D'):
            if sysinfo['SYSTEM']['TILE'] == 4:
                msg = 'Currently in 2x2 tile. Checking for DP chain status'
                sendlog(gotthefunc, msg, 10)
                if sysinfo['SYSTEM']['DPCHAIN'] == 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']['DPCHAIN'] == 1:
                    dplist = [2,3,4,5,6,7,8,9]
                    if any(x in key for x in dplist):
                        dpchain = 1
                    else:
                        dpchain = 0
            if dpchain == 0:
                changeinputallworker = Process(target=changeinputprocess, args=(sysinfo['{0}'.format(key)]['IP'], PORT, sysinfo['{0}'.format(key)]['ID'], input, sysinfo['{0}'.format(key)]['INPUT'], sysinfo['WALL']['MODEL'], socketnum, changeinputallqueue))
                changeinputallworkers.append(changeinputallworker)
                changeinputallworker.start()
                socketnum += 1
            if dpchain == 1:
                changeinputallworker = Process(target=changeinputprocess, args=(sysinfo['{0}'.format(key)]['IP'], PORT, sysinfo['{0}'.format(key)]['ID'], 'dp', sysinfo['{0}'.format(key)]['INPUT'], sysinfo['WALL']['MODEL'], socketnum, changeinputallqueue))
                changeinputallworkers.append(changeinputallworker)
                changeinputallworker.start()
                socketnum += 1
    for i in range(socketnum):
        update_dict(changeinputallqueueresults, changeinputallqueue.get())
    for w in changeinputallworkers:
        w.join()
    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']
    displaynum = sysinfo['SYSTEM']['TARGET']
    end = displaynum + 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']['DPCHAIN'] == 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']['DPCHAIN'] == 1:
            dplist = [2,3,4,5,6,7,8,9]
    while (displaynum < end):
        if displaynum in dplist:
            msg = 'D{0}: Found in dp chain list'.format(displaynum)
            sendlog(gotthefunc, msg, 10)
            changeinputrangeworker = Process(target=changeinputprocess, args=(sysinfo['D{0}'.format(displaynum)]['IP'], PORT, sysinfo['D{0}'.format(displaynum)]['ID'], 'dp', sysinfo['D{0}'.format(displaynum)]['INPUT'], sysinfo['WALL']['MODEL'], socketnum, changeinputrangequeue))
            changeinputrangeworkers.append(changeinputrangeworker)
            changeinputrangeworker.start()
            socketnum += 1
            displaynum += 1
        else:
            msg = 'D{0}: Not found in dp chain list'.format(displaynum)
            sendlog(gotthefunc, msg, 10)
            changeinputrangeworker = Process(target=changeinputprocess, args=(sysinfo['D{0}'.format(displaynum)]['IP'], PORT, sysinfo['D{0}'.format(displaynum)]['ID'], input, sysinfo['D{0}'.format(displaynum)]['INPUT'], sysinfo['WALL']['MODEL'], socketnum, changeinputrangequeue))
            changeinputrangeworkers.append(changeinputrangeworker)
            changeinputrangeworker.start()
            socketnum += 1
            displaynum += 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'):
            powerworker = Process(target=changepowerworker, args=(sysinfo['{0}'.format(key)]['IP'], PORT, 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(ip, port, displaynum, power, socketid, q):
    gotthefunc = inspect.stack()[0][3]
    msg = ('Entered {} function with options {} {}'.format(gotthefunc, displaynum, power))
    sendlog(gotthefunc, msg, 10)
    ts = time()
    s = {}
    s[socketid] = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s[socketid].settimeout(10)
    s[socketid].connect((ip, port))
    output = {}
    output['D{0}'.format(displaynum)] = {}
    output['D{0}'.format(displaynum)]['PWR'] = setpower(displaynum, power,s[socketid])
    sockclose(s[socketid],gotthefunc)
    output['D{0}'.format(displaynum)]['FUNCNAME'] = gotthefunc
    output['D{0}'.format(displaynum)]['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']:
            displaynum = 1
        else:
            displaynum = sysinfo['SYSTEM']['TARGET']
    else:
        displaynum = 1
    wallmodel = sysinfo['WALL']['MODEL']
    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, displaynum, vol[1], wallmodel))
    sendlog(gotthefunc, msg, 10)
    ts = time()
    output = {}
    output['D{0}'.format(displaynum)] = {}
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.settimeout(10)
    s.connect((ip, PORT))
    try:
        with Timeout(3):
            output['D{0}'.format(sysinfo['SYSTEM']['TARGET'])]['VOL'] = setvolume(displaynum,sysinfo['D{0}'.format(sysinfo['SYSTEM']['TARGET'])]['VOL'],vol[1], s)
    except Timeout.Timeout as e:
        pass
        msg = ('Change Volume Timeout')
        sendlog(gotthefunc, msg, 40)
        output['D{0}'.format(sysinfo['SYSTEM']['TARGET'])]['VOL'] = sysinfo['D{0}'.format(sysinfo['SYSTEM']['TARGET'])]['VOL']
    except:
        pass
        msg = ('Unknown Error in {0}'.format(gotthefunc))
        sendlog(gotthefunc, msg, 40)
        err = traceback.format_exc()
        msg = ('Unknown 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']
    returnsaved = saveconfig(displaynum, s)
    sockclose(s,gotthefunc)
    msg = ('Exited {} function'.format(gotthefunc))
    sendlog(gotthefunc, msg, 10)
    return(output)
 
def disabletmworker(sysinfo, port, displaynum, input, wallmodel, save, socketid, q):
    gotthefunc = inspect.stack()[0][3]
    msg = ('Entered {} function with options {} {} {}'.format(gotthefunc, displaynum, input, wallmodel))
    sendlog(gotthefunc, msg, 10)
    ts = time()
    output = {}
    output['D{0}'.format(displaynum)] = {}
    target = sysinfo['SYSTEM']['TARGET']
    s = {}
    s[socketid] = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s[socketid].settimeout(10)
    s[socketid].connect((sysinfo['D{}'.format(displaynum)]['IP'], port))
#    returninput = setinput(displaynum, input, wallmodel, s[socketid])
    if displaynum != sysinfo['SYSTEM']['TARGET']:
        returninput = setinput(displaynum, input, wallmodel, s[socketid])
        msg = returninput
        sendlog(gotthefunc, msg, 10)
        output['D{0}'.format(displaynum)]['INPUT'] = returninput
    returntmmode = settm(displaynum, 0, s[socketid])
    output['D{0}'.format(displaynum)]['SAVED'] = 0
    if save == 1:
        returnsaved = saveconfig(displaynum, s[socketid])
        output['D{0}'.format(displaynum)]['SAVED'] = returnsaved
    else:
        output['D{0}'.format(displaynum)]['SAVED'] = 0
    # **** NEED gettm status here, returning bcmode, hnum, vnum, pos *****
    output['D{0}'.format(displaynum)]['TMMODE'] = returntmmode
    sockclose(s[socketid],gotthefunc)
    output['D{0}'.format(displaynum)]['DISABLETMTIME'] = 'Last process time: {0}'.format(time() - ts)
    q.put(output)
    msg = ('Exited {} function'.format(gotthefunc))
    sendlog(gotthefunc, msg, 10)
    
def disabletm2x2(sysinfo, save=1):
    gotthefunc = inspect.stack()[0][3]
    msg = ('Entered {} function'.format(gotthefunc))
    sendlog(gotthefunc, msg, 10)
    tsmain = time()
    socketnum = 0
    target = sysinfo['SYSTEM']['TARGET']
    displaynum = sysinfo['SYSTEM']['TARGET']
    end = displaynum + 4
    position = 1
    disabletm2x2q = Queue()
    disabletm2x2qresults = {}
    disabletm2x2workers = []
    while (displaynum < end):
#       disabletm2x2worker = Process(target=disabletmworker, args=(sysinfo, PORT, displaynum, sysinfo['SYSTEM']['BASEINPUT'], sysinfo['WALL']['MODEL'] , socketnum, disabletm2x2q))
       disabletm2x2worker = Process(target=disabletmworker, args=(sysinfo, PORT, displaynum, sysinfo['SYSTEM']['DEFAULTINPUT'], sysinfo['WALL']['MODEL'] , save, socketnum, disabletm2x2q))
       disabletm2x2workers.append(disabletm2x2worker)
       socketnum += 1
       displaynum += 1
       position += 1
    for w in disabletm2x2workers:
        w.start()
    for i in range(socketnum):
        update_dict(disabletm2x2qresults, disabletm2x2q.get())
    for w in disabletm2x2workers:
        w.join()
    print('Took {}'.format(time() - tsmain))
    msg = ('Exited {} function'.format(gotthefunc))
    sendlog(gotthefunc, msg, 10)
    return(disabletm2x2qresults)
    
def disabletm4x2(sysinfo, save=1):
    gotthefunc = inspect.stack()[0][3]
    msg = ('Entered {} function'.format(gotthefunc))
    sendlog(gotthefunc, msg, 10)
    tsmain = time()
    socketnum = 0
    target = sysinfo['SYSTEM']['TARGET']
    displaynum = sysinfo['SYSTEM']['TARGET']
    end = displaynum + 8
    position = 1
    disabletm4x2q = Queue()
    disabletm4x2qresults = {}
    disabletm4x2workers = []
    while (displaynum < end):
       disabletm4x2worker = Process(target=disabletmworker, args=(sysinfo, PORT, displaynum, sysinfo['SYSTEM']['DEFAULTINPUT'], sysinfo['WALL']['MODEL'], save, socketnum, disabletm4x2q))
       disabletm4x2workers.append(disabletm4x2worker)
       socketnum += 1
       displaynum += 1
       position += 1
    for w in disabletm4x2workers:
        w.start()
    for i in range(socketnum):
        update_dict(disabletm4x2qresults, disabletm4x2q.get())
    for w in disabletm4x2workers:
        w.join()
    print('Took {}'.format(time() - tsmain))
    msg = ('Exited {} function'.format(gotthefunc))
    sendlog(gotthefunc, msg, 10)
    return(disabletm4x2qresults)
    
def disabletm3x3(sysinfo, save=1):
    gotthefunc = inspect.stack()[0][3]
    msg = ('Entered {} function'.format(gotthefunc))
    sendlog(gotthefunc, msg, 10)
    tsmain = time()
    socketnum = 0
    target = sysinfo['SYSTEM']['TARGET']
    displaynum = sysinfo['SYSTEM']['TARGET']
    end = displaynum + 9
    position = 1
    disabletm3x3q = Queue()
    disabletm3x3qresults = {}
    disabletm3x3workers = []
    while (displaynum < end):
#       disabletm3x3worker = Process(target=disabletmworker, args=(sysinfo, PORT, displaynum, sysinfo['SYSTEM']['BASEINPUT'], sysinfo['WALL']['MODEL'] , socketnum, disabletm3x3q))
       disabletm3x3worker = Process(target=disabletmworker, args=(sysinfo, PORT, displaynum, sysinfo['SYSTEM']['DEFAULTINPUT'], sysinfo['WALL']['MODEL'], save, socketnum, disabletm3x3q))
       disabletm3x3workers.append(disabletm3x3worker)
       socketnum += 1
       displaynum += 1
       position += 1
    for w in disabletm3x3workers:
        w.start()
    for i in range(socketnum):
        update_dict(disabletm3x3qresults, disabletm3x3q.get())
    for w in disabletm3x3workers:
        w.join()
    print('Took {}'.format(time() - tsmain))
    msg = ('Exited {} function'.format(gotthefunc))
    sendlog(gotthefunc, msg, 10)
    return(disabletm3x3qresults)

def logserver():
    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/cdc/cdc.log', mode='a', maxBytes=10*1024*1024, backupCount=0, encoding=None, delay=False)])
    logging.basicConfig(format='%(asctime)s %(processName)-10s %(name)s %(levelname)-8s %(message)s',handlers=[logging.handlers.RotatingFileHandler('/var/log/cdc/cdc.log', mode='a', maxBytes=10000*1024, backupCount=30, encoding=None, delay=False)])
#    logging.basicConfig(format='%(asctime)s %(processName)-10s %(name)s %(levelname)-8s %(message)s',filename='/var/log/cdc/cdc.log')
    tcpserver = LogRecordSocketReceiver()
    tcpserver.serve_until_stopped()
    msg = ('Exited {} function'.format(gotthefunc))
    sendlog(gotthefunc, msg, 10)

def main():
    gotthefunc = inspect.stack()[0][3]
    msg = ('Entered {} function'.format(gotthefunc))
    sendlog(gotthefunc, msg, 10)

    parser = argparse.ArgumentParser(description='Cloud Display 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)

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

    # Build master systemwide sysinfo dictionary
    sysinfo = {}
    sysinfo['SYSTEM'] = {}
    sysinfo['WALL'] = {}

    # Read config
    config = configparser.ConfigParser()
    try:
        config.read(['/etc/cdc/cdc.conf'])
    except configparser.Error as e:
        msg = ('Unable to read configuration file /etc/cdc/cdc.conf! Halting!')
        sendlog(gotthefunc, msg, 40)
        sys.exit()
    except:
        msg = ('Unknown Error in {0} Reading Config! Halting!'.format(gotthefunc))
        sendlog(gotthefunc, msg, 40)
        err = traceback.format_exc()
        msg = ('Unknown Error Detail: {0}'.format(err))
        sendlog(gotthefunc, msg, 10)
        sys.exit()
    else:
        msg = ('CONFIG: Loaded config file')
        sendlog(gotthefunc, msg, 10)
    # 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, 40)
        sys.exit()
    except configparser.Error as e:
        msg = ('Config read entry system license key error! Halting!')
        sendlog(gotthefunc, msg, 40)
        sys.exit()
    except:
        msg = ('Unknown Error in {0} Reading Config! Halting!'.format(gotthefunc))
        sendlog(gotthefunc, msg, 40)
        err = traceback.format_exc()
        msg = ('Unknown Error Detail: {0}'.format(err))
        sendlog(gotthefunc, msg, 10)
        sys.exit()
    else:
        msg = ('CONFIG: Loaded license key')
        sendlog(gotthefunc, msg, 10)
    # Get machine mac address
    try:
        sysinfo['SYSTEM']['MAC'] = getmac("eth0")
    except:
        msg = ('Unknown Error in {0} Getting MAC Address! Halting!'.format(gotthefunc))
        sendlog(gotthefunc, msg, 40)
        err = traceback.format_exc()
        msg = ('Unknown Error Detail: {0}'.format(err))
        sendlog(gotthefunc, msg, 10)
        sys.exit()
    else:
        msg = ('CONFIG: Got MAC address')
        sendlog(gotthefunc, msg, 10)
    try:
        netifaces.interfaces()
        sysinfo['SYSTEM']['MYIP'] = netifaces.ifaddresses('eth0')[netifaces.AF_INET][0]['addr']
    except:
        msg = ('Unknown Error in {0} Getting Local IP Address! Halting!'.format(gotthefunc))
        sendlog(gotthefunc, msg, 40)
        err = traceback.format_exc()
        msg = ('Unknown Error Detail: {0}'.format(err))
        sendlog(gotthefunc, msg, 10)
        sys.exit()
    else:
        msg = ('CONFIG: Retrieved my ip: {}'.format(sysinfo['SYSTEM']['MYIP']))
        print(msg)
        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, 40)
        sysinfo['SYSTEM']['LOGLEVEL'] = '20'
        pass
    except configparser.Error as e:
        msg = ('Config read entry system loglevel error! Halting!')
        sendlog(gotthefunc, msg, 40)
        sys.exit()
    except:
        msg = ('Unknown Error in {0} Reading Config! Halting!'.format(gotthefunc))
        sendlog(gotthefunc, msg, 40)
        err = traceback.format_exc()
        msg = ('Unknown Error Detail: {0}'.format(err))
        sendlog(gotthefunc, msg, 10)    
        sys.exit()
    else:
        msg = ('CONFIG: Got logging level')
        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, 40)
        sysinfo['SYSTEM']['CONNECTION'] = 'ip'
        pass
    except configparser.Error as e:
        msg = ('Config read entry system connection error! Halting!')
        sendlog(gotthefunc, msg, 40)
        sys.exit()
    except:
        msg = ('Unknown Error in {0} Reading Config! Halting!'.format(gotthefunc))
        sendlog(gotthefunc, msg, 40)
        err = traceback.format_exc()
        msg = ('Unknown Error Detail: {0}'.format(err))
        sendlog(gotthefunc, msg, 10)
        sys.exit()
    else:
        msg = ('CONFIG: Got connection type')
        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('system', 'serialport')
        except (configparser.NoOptionError, configparser.InterpolationMissingOptionError):
            msg = ('No serial port specified in configuration file. Defaulting to /dev/ttyUSB0')
            sendlog(gotthefunc, msg, 40)
            sysinfo['SYSTEM']['serialport'] = '/dev/ttyUSB0'
            pass
        except configparser.Error as e:
            msg = ('Config read entry system serial port error! Halting!')
            sendlog(gotthefunc, msg, 40)
            sys.exit()
        except:
            msg = ('Unknown Error in {0} Reading Config! Halting!'.format(gotthefunc))
            sendlog(gotthefunc, msg, 40)
            err = traceback.format_exc()
            msg = ('Unknown Error Detail: {0}'.format(err))
            sendlog(gotthefunc, msg, 10)
            sys.exit()
    else:
        msg = ('Invalid connection type specified in configuration file. Halting!')
        sendlog(gotthefunc, msg, 40)
        sys.exit()
    try:
        sysinfo['SYSTEM']['HTTPPROXY'] = config.get('system', 'httpproxy')
    except (configparser.NoOptionError, configparser.InterpolationMissingOptionError):
        msg = ('No proxy specified in configuration file. Moving on.')
        sendlog(gotthefunc, msg, 40)
        pass
    except configparser.Error as e:
        msg = ('No proxy specified in configuration file. Moving on.')
        sendlog(gotthefunc, msg, 10)
        pass
    except:
        msg = ('Unknown Error in {0} Reading Config! Halting!'.format(gotthefunc))
        sendlog(gotthefunc, msg, 40)
        err = traceback.format_exc()
        msg = ('Unknown Error in {0} Detail: {1}'.format(gotthefunc,err))
        print(msg)
        sendlog(gotthefunc, msg, 10)
        sys.exit()
    else:
        msg = ('CONFIG: Got http proxy')
        sendlog(gotthefunc, msg, 10)

    try:
        sysinfo['WALL']['MODEL'] = config.get('wall', 'model')
    except (configparser.NoOptionError, configparser.InterpolationMissingOptionError):
        msg = ('No monitor model in configuration file! Halting!')
        sendlog(gotthefunc, msg, 40)
        sys.exit()
    except configparser.Error as e:
        msg = ('Config read entry wall model error! Halting!')
        sendlog(gotthefunc, msg, 40)
        sys.exit()
    except:
        msg = ('Unknown Error in {0} Reading Config! Halting!'.format(gotthefunc))
        sendlog(gotthefunc, msg, 40)
        err = traceback.format_exc()
        msg = ('Unknown Error Detail: {0}'.format(err))
        sendlog(gotthefunc, msg, 10)
        sys.exit()
    try:
        sysinfo['WALL']['WIRING'] = config.get('wall', 'wiring')
    except (configparser.NoOptionError, configparser.InterpolationMissingOptionError):
        msg = ('No wiring type specified in configuration file. Defaulting to zig-zag!')
        sendlog(gotthefunc, msg, 40)
        sysinfo['WALL']['WIRING'] = 'zig-zag'
        pass
    except configparser.Error as e:
        msg = ('Config read entry wall wiring error! Halting!')
        sendlog(gotthefunc, msg, 40)
        sys.exit()
    except:
        msg = ('Unknown Error in {0} Reading Config! Halting!'.format(gotthefunc))
        sendlog(gotthefunc, msg, 40)
        err = traceback.format_exc()
        msg = ('Unknown 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, 40)
        sysinfo['SYSTEM']['DEFAULTINPUT'] = 'dvi'
        pass
    except configparser.Error as e:
        msg = ('Config read entry wall defaultinput error! Halting!')
        sendlog(gotthefunc, msg, 40)
        sys.exit()
    except:
        msg = ('Unknown Error in {0} Reading Config! Halting!'.format(gotthefunc))
        sendlog(gotthefunc, msg, 40)
        err = traceback.format_exc()
        msg = ('Unknown Error Detail: {0}'.format(err))
        sendlog(gotthefunc, msg, 10)
        sys.exit()
    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, 40)
        sysinfo['SYSTEM']['MATRIXIP'] = None
        pass
    except configparser.Error as e:
        msg = ('Config read entry wall matrix ip error! Halting!')
        sendlog(gotthefunc, msg, 40)
        sys.exit()
    except:
        msg = ('Unknown Error in {0} Reading Config! Halting!'.format(gotthefunc))
        sendlog(gotthefunc, msg, 40)
        err = traceback.format_exc()
        msg = ('Unknown Error Detail: {0}'.format(err))
        sendlog(gotthefunc, msg, 10)
        sys.exit()
    else:
        msg = ('CONFIG: Retrieved matrix ip: {}'.format(sysinfo['SYSTEM']['MATRIXIP']))
        print(msg)
        sendlog(gotthefunc, msg, 10)
    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', logging.handlers.DEFAULT_TCP_LOGGING_PORT)
    logger.addHandler(sock)
    if cliargs.consolelogs:
        consolelog = logging.StreamHandler(sys.stdout)
        logger.addHandler(consolelog)
    sleep(2)

#    loglevel = config.get('system', 'loglevel')
    msg = 'Log test'
    sendlog(gotthefunc, msg, 10)

    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']

    # Test network connection
    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, 40)
            err = traceback.format_exc()
            msg = ('Unknown 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(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)
###### Old network check. Replaced with default gateway ping plus testing monitors with ping. Will enhance this soon with serial comparison with 
###### previous startup data saved in sqlite database.  
#    msg = waitfornetwork(defaultgateway)
#    sendlog(gotthefunc, msg, 10)
        
    if sysinfo['SYSTEM']['CONNECTION'] == 'ip':
        socketnum = 0
        pingqueue = Queue()
        pingworkers = []
        for ipid, ipaddr in IP.items():
            now = datetime.datetime.now()
            pingworker = Process(target=ping, args=(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))
            print(msg)
            sendlog(gotthefunc, msg, 10)
            if val['UP'] == False:
                sendlog(gotthefunc, msg, 50)
                subject = ('MONITOR {} DOWN!'.format(key))
                msg = ('MONITOR {} DOWN!'.format(key))
                emailaddresses = ['sloeckle@lucidnetworks.net']
                smtphost = 'localhost'
                sendemail(emailaddresses,smtphost,subject,msg)
                sleep(5)
                raise Exception(msg)

##### Borrowed from declientlib. Added as placeholder. Function copied to cdclib but needs to be converted to cdc.            
#            tempjobsdata['SYSTEM']['CONFIG']['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['SYSTEM']['CONNECTION'], ipaddr, PORT, socketnum, startupqueue))
            startupworkers.append(startupworker)
            startupworker.start()
            socketnum += 1
        sysinfo['SYSTEM']['DISPLAYS'] = socketnum
        startupresults = {}
        for i in range(socketnum):
            update_dict(startupresults, startupqueue.get())
        for w in startupworkers:
            w.join()
        sortedresults = collections.OrderedDict(sorted(startupresults.items()))
        for key,val in sortedresults.items():
            msg = ("{0} = {1}".format(key,val))
            sendlog(gotthefunc, msg, 10)
        update_dict(sysinfo, startupresults)
        
    if sysinfo['SYSTEM']['CONNECTION'] == 'serial':

        sendlog(gotthefunc, msg, 10)
        socketnum = 0
        serialport = serial.Serial('/dev/ttyUSB0', baudrate=9600, bytesize=8, parity=serial.PARITY_NONE, stopbits=1, timeout=5)
        for i in range(sysinfo['SYSTEM']['DISPLAYS']):
            startupresults = startupdisplaystatus(connection=sysinfo['SYSTEM']['CONNECTION'], serial=serialport)
            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

    tsmain = time()
    socketnum = 0
    setdefaultqueue = Queue()
    setdefaultworkers = []
    for key, value in sysinfo.items():
        if key.startswith('D'):
            setdefaultworker = Process(target=setdefaults, args=(sysinfo['{0}'.format(key)]['IP'], PORT, sysinfo['{0}'.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()
    sortedresults = collections.OrderedDict(sorted(setdefaultresults.items()))
    for key,val in sortedresults.items():
        msg = ("{0} = {1}".format(key,val))
        sendlog(gotthefunc, msg, 10)
    msg = ('Took {}'.format(time() - tsmain))
    sendlog(gotthefunc, msg, 10)
    # Merge setdefault results into master sysinfo dictionary
    update_dict(sysinfo, setdefaultresults)

    # If it exists, load old state file in case there was a power issue

    if os.path.exists("/var/lib/cdc/cdc.state"):
        with open('/var/lib/cdc/cdc.state', 'r') as f:
            laststate = json.load(f)
        f.close()
        sysinfo['SYSTEM']['LASTUPDATED'] = laststate['SYSTEM']['LASTUPDATED']
        sysinfo['SYSTEM']['COMMAND'] = laststate['SYSTEM']['COMMAND']
        sysinfo['SYSTEM']['TILE'] = laststate['SYSTEM']['TILE']
        sysinfo['SYSTEM']['BASEINPUT'] = laststate['SYSTEM']['BASEINPUT']
        sysinfo['SYSTEM']['DPCHAIN'] = laststate['SYSTEM']['DPCHAIN']
        for key, value in sysinfo.items():
            if key.startswith('D'):
                sysinfo['{0}'.format(key)]['LASTINPUT'] = laststate['{0}'.format(key)]['LASTINPUT']
    else:
        laststate = {}
        sysinfo['SYSTEM']['LASTUPDATED'] = 0
        sysinfo['SYSTEM']['COMMAND'] = None
        sysinfo['SYSTEM']['TILE'] = 0
        sysinfo['SYSTEM']['BASEINPUT'] = None
        sysinfo['SYSTEM']['DPCHAIN'] = 0
        # Set LASTINPUT to default input from config if LASTINPUT has never been set
        for key, value in sysinfo.items():
            if key.startswith('D'):
                sysinfo['{0}'.format(key)]['LASTINPUT'] = config.get('wall', 'defaultinput')

#    if sysinfo['SYSTEM']['TILE'] == 0:
#        cmdresponse = disabletm2x2(sysinfo)
#        msg = cmdresponse
#        sendlog(gotthefunc, msg, 10)
#        update_dict(sysinfo, cmdresponse)
#
#    if sysinfo['SYSTEM']['TILE'] == 4:
#        cmdresponse = buildtm2x2(sysinfo)
#        msg = cmdresponse
#        sendlog(gotthefunc, msg, 10)
#        update_dict(sysinfo, cmdresponse)


# Unused until 9 display programming compelted
#
#    if sysinfo['SYSTEM']['TILE'] = 9:
#        cmdresponse = buildtm2x2(sysinfo)
#        print(cmdresponse)
#        update(sysinfo, cmdresponse)
        

#    sysinfo['SYSTEM']['GETCMDRUNNING'] = 0

    # Let's compare old state to sysinfo

#    diff,changes = dict_diff(laststate,sysinfo)
#    if diff:
#        sortedresults = collections.OrderedDict(sorted(diff.items()))
#        for key,val in sortedresults.items():
#            print("{0} = {1}".format(key,val))
#        print(diff)
#    if changes:
#        sysinfo.update(changes)
#        savestate(sysinfo)
#        sortedresults = collections.OrderedDict(sorted(changes.items()))
#        for key,val in sortedresults.items():
#            print("{0} = {1}".format(key,val))
#        print(changes)

    print(sysinfo)
    # Begin cloud server query for data
    csloop = 0
    while True:
        try:
            with Timeout(3):
                olddict = sysinfo.copy()
        except Timeout.Timeout as e:
            pass
            msg = ('CSLoop Start Class Timeout')
            sendlog(gotthefunc, msg, 40)
        except:
            pass
            msg = ('Unknown Error 1 in {0}'.format(gotthefunc))
            sendlog(gotthefunc, msg, 40)
            err = traceback.format_exc()
            msg = ('Unknown Error 1 Detail: {0}'.format(err))
            sendlog(gotthefunc, msg, 10)
        try:
            with Timeout(3):
                cmd = fetchcmd(sysinfo)
        except Timeout.Timeout as e:
            pass
            msg = ('CSLoop cmd = fetchcmd Class Timeout')
            sendlog(gotthefunc, msg, 40)
        except:
            pass
            msg = ('Unknown Error 2 in {0}'.format(gotthefunc))
            sendlog(gotthefunc, msg, 40)
            err = traceback.format_exc()
            msg = ('Unknown 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:
            with Timeout(3):
                update_dict(sysinfo, cmd)
        except Timeout.Timeout as e:
            pass
            msg = ('CSLoop update_dict Class Timeout')
            sendlog(gotthefunc, msg, 40)
        except:
            pass
            msg = ('Unknown Error 3 in {0}'.format(gotthefunc))
            sendlog(gotthefunc, msg, 40)
            err = traceback.format_exc()
            msg = ('Unknown 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':
            if sysinfo['SYSTEM']['COMMAND'] == 'input_dvi':
                sysinfo['SYSTEM']['DPCHAINPREV'] = sysinfo['SYSTEM']['DPCHAIN']
                sysinfo['SYSTEM']['DPCHAIN'] = 1
                if sysinfo['SYSTEM']['DPCHAINPREV'] == 0:
                    try:
                        with Timeout(10):
                            cmdresponse = changeinputall(sysinfo, 'dvi')
                    except Timeout.Timeout as e:
                        pass
                        msg = ('CSLoop changeinputall dvi Class Timeout')
                        sendlog(gotthefunc, msg, 40)
                    except:
                        pass
                        msg = ('Unknown Error 4 in {0}'.format(gotthefunc))
                        sendlog(gotthefunc, msg, 40)
                        err = traceback.format_exc()
                        msg = ('Unknown Error 4 Detail: {0}'.format(err))
                        sendlog(gotthefunc, msg, 10)
                else:
                    try:
                        with Timeout(10):
                            cmdresponse = changeinput(sysinfo, 'dvi')
                    except Timeout.Timeout as e:
                        pass
                        msg = ('CSLoop changeinput dvi Class Timeout')
                        sendlog(gotthefunc, msg, 40)
                    except:
                        pass
                        msg = ('Unknown Error 5 in {0}'.format(gotthefunc))
                        sendlog(gotthefunc, msg, 40)
                        err = traceback.format_exc()
                        msg = ('Unknown 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']['DPCHAINPREV'] = sysinfo['SYSTEM']['DPCHAIN']
                sysinfo['SYSTEM']['DPCHAIN'] = 1
                try:
                    with Timeout(10):
                        cmdresponse = changeinputrange(sysinfo, 'dvi', 4)
                except Timeout.Timeout as e:
                    pass
                    msg = ('CSLoop changeinputrange dvi Class Timeout')
                    sendlog(gotthefunc, msg, 40)
                except:
                    pass
                    msg = ('Unknown Error 6 in {0}'.format(gotthefunc))
                    sendlog(gotthefunc, msg, 40)
                    err = traceback.format_exc()
                    msg = ('Unknown Error 6 Detail: {0}'.format(err))
                    sendlog(gotthefunc, msg, 10)
                update_dict(sysinfo, cmdresponse)
            if sysinfo['SYSTEM']['COMMAND'] == 'input_dvi_all':
                sysinfo['SYSTEM']['DPCHAINPREV'] = sysinfo['SYSTEM']['DPCHAIN']
                sysinfo['SYSTEM']['DPCHAIN'] = 1
                try:
                    with Timeout(10):
                        cmdresponse = changeinputall(sysinfo, 'dvi')
                except Timeout.Timeout as e:
                    pass
                    msg = ('CSLoop changeinputall dvi 2 Class Timeout')
                    sendlog(gotthefunc, msg, 40)
                except:
                    pass
                    msg = ('Unknown Error 7 in {0}'.format(gotthefunc))
                    sendlog(gotthefunc, msg, 40)
                    err = traceback.format_exc()
                    msg = ('Unknown 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']['DPCHAINPREV'] = sysinfo['SYSTEM']['DPCHAIN']
                sysinfo['SYSTEM']['DPCHAIN'] = 1
                if sysinfo['SYSTEM']['DPCHAINPREV'] == 0:
                    try:
                        with Timeout(10):
                            cmdresponse = changeinputall(sysinfo, 'dp')
                    except Timeout.Timeout as e:
                        pass
                        msg = ('CSLoop changeinputall dp Class Timeout')
                        sendlog(gotthefunc, msg, 40)
                    except:
                        pass
                        msg = ('Unknown Error 4 in {0}'.format(gotthefunc))
                        sendlog(gotthefunc, msg, 40)
                        err = traceback.format_exc()
                        msg = ('Unknown Error 4 Detail: {0}'.format(err))
                        sendlog(gotthefunc, msg, 10)
                else:
                    try:
                        with Timeout(10):
                            cmdresponse = changeinput(sysinfo, 'dp')
                    except Timeout.Timeout as e:
                        pass
                        msg = ('CSLoop changeinput dp Class Timeout')
                        sendlog(gotthefunc, msg, 40)
                    except:
                        pass
                        msg = ('Unknown Error 5 in {0}'.format(gotthefunc))
                        sendlog(gotthefunc, msg, 40)
                        err = traceback.format_exc()
                        msg = ('Unknown Error 5 Detail: {0}'.format(err))
                        sendlog(gotthefunc, msg, 10)
                update_dict(sysinfo, cmdresponse)
                sysinfo['SYSTEM']['BASEINPUT'] = 'dp'
            if sysinfo['SYSTEM']['COMMAND'] == 'input_hdmi':
## Temporary until I can get this to only affect drequested screen numbers
                sysinfo['SYSTEM']['DPCHAINPREV'] = sysinfo['SYSTEM']['DPCHAIN']
                sysinfo['SYSTEM']['DPCHAIN'] = 1
                try:
                    with Timeout(10):
                        cmdresponse = changeinput(sysinfo, 'hdmi')
                except Timeout.Timeout as e:
                    pass
                    msg = ('CSLoop changeinput hdmi Class Timeout')
                    sendlog(gotthefunc, msg, 40)
                except:
                    pass
                    msg = ('Unknown Error 8 in {0}'.format(gotthefunc))
                    sendlog(gotthefunc, msg, 40)
                    err = traceback.format_exc()
                    msg = ('Unknown Error 8 Detail: {0}'.format(err))
                    sendlog(gotthefunc, msg, 10)
                update_dict(sysinfo, cmdresponse)
                sysinfo['SYSTEM']['BASEINPUT'] = 'hdmi'
            if sysinfo['SYSTEM']['COMMAND'] == 'input_hdmi_all':
                sysinfo['SYSTEM']['DPCHAINPREV'] = sysinfo['SYSTEM']['DPCHAIN']
                sysinfo['SYSTEM']['DPCHAIN'] = 1
                try:
                    with Timeout(10):
                        cmdresponse = changeinputall(sysinfo, 'hdmi')
                except Timeout.Timeout as e:
                    pass
                    msg = ('CSLoop changeinputall hdmi Class Timeout')
                    sendlog(gotthefunc, msg, 40)
                except:
                    pass
                    msg = ('Unknown Error 9 in {0}'.format(gotthefunc))
                    sendlog(gotthefunc, msg, 40)
                    err = traceback.format_exc()
                    msg = ('Unknown 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']['DPCHAINPREV'] = sysinfo['SYSTEM']['DPCHAIN']
                sysinfo['SYSTEM']['DPCHAIN'] = 0
                try:
                    with Timeout(10):
                        cmdresponse = changeinputrange(sysinfo, 'hdmi', 4)
                except Timeout.Timeout as e:
                    pass
                    msg = ('CSLoop changeinputrange hdmi Class Timeout')
                    sendlog(gotthefunc, msg, 40)
                except:
                    pass
                    msg = ('Unknown Error 10 in {0}'.format(gotthefunc))
                    sendlog(gotthefunc, msg, 40)
                    err = traceback.format_exc()
                    msg = ('Unknown Error 10 Detail: {0}'.format(err))
                    sendlog(gotthefunc, msg, 10)
                update_dict(sysinfo, cmdresponse)
            if sysinfo['SYSTEM']['COMMAND'] == 'input_hdmi_splitter':
                sysinfo['SYSTEM']['DPCHAINPREV'] = sysinfo['SYSTEM']['DPCHAIN']
                sysinfo['SYSTEM']['DPCHAIN'] = 0
                try:
                    with Timeout(10):
                        cmdresponse = changeinput(sysinfo, 'hdmi')
                except Timeout.Timeout as e:
                    pass
                    msg = ('CSLoop changeinputall 2 hdmi Class Timeout')
                    sendlog(gotthefunc, msg, 40)
                except:
                    pass
                    msg = ('Unknown Error 11 in {0}'.format(gotthefunc))
                    sendlog(gotthefunc, msg, 40)
                    err = traceback.format_exc()
                    msg = ('Unknown 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_matrix':
                sysinfo['SYSTEM']['DPCHAINPREV'] = sysinfo['SYSTEM']['DPCHAIN']
                sysinfo['SYSTEM']['DPCHAIN'] = 0
                sysinfo['SYSTEM']['USEMATRIX'] = 1
                try:
                    with Timeout(10):
                        cmdresponse = changeinput(sysinfo, 'hdmi')
                except Timeout.Timeout as e:
                    pass
                    msg = ('CSLoop changeinputall 2 hdmi Class Timeout')
                    sendlog(gotthefunc, msg, 40)
                except:
                    pass
                    msg = ('Unknown Error 20 in {0}'.format(gotthefunc))
                    sendlog(gotthefunc, msg, 40)
                    err = traceback.format_exc()
                    msg = ('Unknown 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']['DPCHAINPREV'] = sysinfo['SYSTEM']['DPCHAIN']
                sysinfo['SYSTEM']['DPCHAIN'] = 1
                try:
                    with Timeout(10):
                        cmdresponse = changeinput(sysinfo, 'option')
                except Timeout.Timeout as e:
                    pass
                    msg = ('CSLoop changeinput optioni Class Timeout')
                    sendlog(gotthefunc, msg, 40)
                except:
                    pass
                    msg = ('Unknown Error 12 in {0}'.format(gotthefunc))
                    sendlog(gotthefunc, msg, 40)
                    err = traceback.format_exc()
                    msg = ('Unknown Error 12 Detail: {0}'.format(err))
                    sendlog(gotthefunc, msg, 10)
                update_dict(sysinfo, cmdresponse)
            if sysinfo['SYSTEM']['COMMAND'] == 'tile_8_on':
                try:
                    with Timeout(130):
                        cmdresponse = buildtmwork(sysinfo,4,2)
                except Timeout.Timeout as e:
                    pass
                    msg = ('CSLoop buildtmwork 4x2 Class Timeout')
                    sendlog(gotthefunc, msg, 40)
                except:
                    pass
                    msg = ('Unknown Error 13 in {0}'.format(gotthefunc))
                    sendlog(gotthefunc, msg, 40)
                    err = traceback.format_exc()
                    msg = ('Unknown 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':
                try:
                    with Timeout(130):
                        cmdresponse = buildtmwork(sysinfo,3,3)
                except Timeout.Timeout as e:
                    pass
                    msg = ('CSLoop buildtmwork 3x3 Class Timeout')
                    sendlog(gotthefunc, msg, 40)
                except:
                    pass
                    msg = ('Unknown Error 13 in {0}'.format(gotthefunc))
                    sendlog(gotthefunc, msg, 40)
                    err = traceback.format_exc()
                    msg = ('Unknown 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_on':
                if sysinfo['SYSTEM']['TILE'] == 8:
                    try:
                        with Timeout(250):
                            cmdresponse = disabletm4x2(sysinfo,0)
                    except Timeout.Timeout as e:
                        pass
                        msg = ('CSLoop disabletmwork 4x2 Class Timeout')
                        sendlog(gotthefunc, msg, 40)
                    except:
                        pass
                        msg = ('Unknown Error 16 in {0}'.format(gotthefunc))
                        sendlog(gotthefunc, msg, 40)
                        err = traceback.format_exc()
                        msg = ('Unknown Error 16 Detail: {0}'.format(err))
                        sendlog(gotthefunc, msg, 10)
                    msg = cmdresponse
                    sendlog(gotthefunc, msg, 10)
                    update_dict(sysinfo, cmdresponse)
                    sysinfo['SYSTEM']['TILE'] = 0
                if sysinfo['SYSTEM']['TILE'] == 9:
                    try:
                        with Timeout(250):
                            cmdresponse = disabletm3x3(sysinfo,0)
                    except Timeout.Timeout as e:
                        pass
                        msg = ('CSLoop disabletmwork 3x3 Class Timeout')
                        sendlog(gotthefunc, msg, 40)
                    except:
                        pass
                        msg = ('Unknown Error 16 in {0}'.format(gotthefunc))
                        sendlog(gotthefunc, msg, 40)
                        err = traceback.format_exc()
                        msg = ('Unknown Error 16 Detail: {0}'.format(err))
                        sendlog(gotthefunc, msg, 10)
                    msg = cmdresponse
                    sendlog(gotthefunc, msg, 10)
                    update_dict(sysinfo, cmdresponse)
                    sysinfo['SYSTEM']['TILE'] = 0
                if sysinfo['SYSTEM']['USEMATRIX'] == 1:
                    d = sysinfo['SYSTEM']['TARGET']
                    outputnum = sysinfo['SYSTEM']['TARGET']
                    sysinfo['SYSTEM']['MATRIXCOMMANDS']
                    while outputnum < d+4:
                        outputletter = chr(96 + outputnum)
                        sysinfo['SYSTEM']['MATRIXCOMMANDS'].append([d,'{}'.format(outputletter)])
                        outputnum += 1
#                    sysinfo['SYSTEM']['MATRIXCOMMANDS'] = [[d,'a'],[d,'b'],[d,'c'],[d,'d']]
                try:
                    with Timeout(30):
                        cmdresponse = buildtmwork(sysinfo,2,2)
                except Timeout.Timeout as e:
                    pass
                    msg = ('CSLoop buildtmwork 2x2 Class Timeout')
                    sendlog(gotthefunc, msg, 40)
                except:
                    pass
                    msg = ('Unknown Error 14 in {0}'.format(gotthefunc))
                    sendlog(gotthefunc, msg, 40)
                    err = traceback.format_exc()
                    msg = ('Unknown 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':
                if sysinfo['SYSTEM']['TILE'] == 4:
                    try:
                        with Timeout(20):
                            cmdresponse = disabletm2x2(sysinfo)
                    except Timeout.Timeout as e:
                        pass
                        msg = ('CSLoop disabletmwork 2x2 Class Timeout')
                        sendlog(gotthefunc, msg, 40)
                    except:
                        pass
                        msg = ('Unknown Error 15 in {0}'.format(gotthefunc))
                        sendlog(gotthefunc, msg, 40)
                        err = traceback.format_exc()
                        msg = ('Unknown Error 15 Detail: {0}'.format(err))
                        sendlog(gotthefunc, msg, 10)
                    msg = cmdresponse
                    sendlog(gotthefunc, msg, 10)
                    update_dict(sysinfo, cmdresponse)
                    sysinfo['SYSTEM']['TILE'] = 0
                if sysinfo['SYSTEM']['TILE'] == 8:
                    try:
                        with Timeout(250):
                            cmdresponse = disabletm4x2(sysinfo)
                    except Timeout.Timeout as e:
                        pass
                        msg = ('CSLoop disabletmwork 4x2 Class Timeout')
                        sendlog(gotthefunc, msg, 40)
                    except:
                        pass
                        msg = ('Unknown Error 16 in {0}'.format(gotthefunc))
                        sendlog(gotthefunc, msg, 40)
                        err = traceback.format_exc()
                        msg = ('Unknown Error 16 Detail: {0}'.format(err))
                        sendlog(gotthefunc, msg, 10)
                    msg = cmdresponse
                    sendlog(gotthefunc, msg, 10)
                    update_dict(sysinfo, cmdresponse)
                    sysinfo['SYSTEM']['TILE'] = 0
                if sysinfo['SYSTEM']['TILE'] == 9:
                    try:
                        with Timeout(250):
                            cmdresponse = disabletm3x3(sysinfo)
                    except Timeout.Timeout as e:
                        pass
                        msg = ('CSLoop disabletmwork 3x3 Class Timeout')
                        sendlog(gotthefunc, msg, 40)
                    except:
                        pass
                        msg = ('Unknown Error 16 in {0}'.format(gotthefunc))
                        sendlog(gotthefunc, msg, 40)
                        err = traceback.format_exc()
                        msg = ('Unknown Error 16 Detail: {0}'.format(err))
                        sendlog(gotthefunc, msg, 10)
                    msg = cmdresponse
                    sendlog(gotthefunc, msg, 10)
                    update_dict(sysinfo, cmdresponse)
                    sysinfo['SYSTEM']['TILE'] = 0
            if sysinfo['SYSTEM']['COMMAND'].startswith('volume'):
                vol = sysinfo['SYSTEM']['COMMAND'].split("_")
                try:
                    with Timeout(10):
                        cmdresponse = changevolume(sysinfo)
                except Timeout.Timeout as e:
                    pass
                    msg = ('CSLoop changevolume Class Timeout')
                    sendlog(gotthefunc, msg, 40)
                except:
                    pass
                    msg = ('Unknown Error 17 in {0}'.format(gotthefunc))
                    sendlog(gotthefunc, msg, 40)
                    err = traceback.format_exc()
                    msg = ('Unknown Error 17 Detail: {0}'.format(err))
                    sendlog(gotthefunc, msg, 10)
                update_dict(sysinfo, cmdresponse)
                msg = cmdresponse
                sendlog(gotthefunc, msg, 10)
            if sysinfo['SYSTEM']['COMMAND'] == 'display_all_power_off':
                try:
                    with Timeout(10):
                        changepower(sysinfo, 0)
                except Timeout.Timeout as e:
                    pass
                    msg = ('CSLoop changepower off Class Timeout')
                    sendlog(gotthefunc, msg, 40)
                except:
                    pass
                    msg = ('Unknown Error 18 in {0}'.format(gotthefunc))
                    sendlog(gotthefunc, msg, 40)
                    err = traceback.format_exc()
                    msg = ('Unknown Error 18 Detail: {0}'.format(err))
                    sendlog(gotthefunc, msg, 10)
            if sysinfo['SYSTEM']['COMMAND'] == 'display_all_power_on':
                try:
                    with Timeout(10):
                        changepower(sysinfo, 1)
                except Timeout.Timeout as e:
                    pass
                    msg = ('CSLoop changepower on Class Timeout')
                    sendlog(gotthefunc, msg, 40)
                except:
                    pass
                    msg = ('Unknown Error 19 in {0}'.format(gotthefunc))
                    sendlog(gotthefunc, msg, 40)
                    err = traceback.format_exc()
                    msg = ('Unknown 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
            
#        diff = dict_diff(olddict,sysinfo)
#        if diff:
#            print(diff)
        sleep(1)
        if csloop >= 60:
            savestate(sysinfo)
            csloop = 0
        else:
            csloop += 1
    
    msg = ('Exited {} function'.format(gotthefunc))
    sendlog(gotthefunc, msg, 10)
    logworker.join()


if __name__ == '__main__':
   main()
