Exemplo n.º 1
0
    def __init__(self):
        self.OPTION_USE_3_WIRE_VALVES = self.getConfigValueByName(
            "use3WireValves")
        self.OPTION_RESTART_FANTIMER_AFTER_POUR = self.getConfigValueByName(
            "restartFanAfterPour")
        setupSocket = MCAST_RETRY_ATTEMPTS
        if GPIO_IMPORT_SUCCESSFUL:
            GPIO.setwarnings(False)
            GPIO.setmode(GPIO.BOARD)  # Broadcom pin-numbering scheme
        self.alaModeReconfig = False

        while setupSocket > 0:
            try:
                #multicast socket
                self.mcast = socket.socket(socket.AF_INET, socket.SOCK_DGRAM,
                                           socket.IPPROTO_UDP)
                self.mcast.setsockopt(socket.IPPROTO_IP,
                                      socket.IP_MULTICAST_LOOP, 1)

                mreq = struct.pack("4sl", socket.inet_aton(MCAST_GRP),
                                   socket.INADDR_ANY)
                self.mcast.setsockopt(socket.IPPROTO_IP,
                                      socket.IP_ADD_MEMBERSHIP, mreq)

                setupSocket = 0
            except socket.error as msg:
                setupSocket = setupSocket - 1
                log(msg.strerror + " - Sleeping to try again")
                time.sleep(MCAST_RETRY_SLEEP_SEC)

        if setupSocket == MCAST_RETRY_ATTEMPTS:
            log(str(setupSocket))
            log("FATAL: Unable to setup socket")
            quit()

        self.valvesState = []
        self.fanTimer = None
        self.valvePowerTimer = None
        if int(self.OPTION_USE_3_WIRE_VALVES) == 1:
            self.valvePowerTimer = Timer(OPTION_VALVEPOWERON,
                                         self.valveStopPower)

        self.updateFlowmeterConfig()
        self.updateValvePins()

        self.commandserver = CommandTCPServer(('localhost', MCAST_PORT),
                                              CommandTCPHandler)
        self.commandserver.pintdispatch = self
        self.fanControl = FanControlThread("fanControl1", self)
        self.flowmonitor = FlowMonitor(self)
Exemplo n.º 2
0
class PintDispatch(object):
    def __init__(self):
        self.OPTION_USE_3_WIRE_VALVES = self.getConfigValueByName(
            "use3WireValves")
        self.OPTION_RESTART_FANTIMER_AFTER_POUR = self.getConfigValueByName(
            "restartFanAfterPour")
        setupSocket = MCAST_RETRY_ATTEMPTS
        if GPIO_IMPORT_SUCCESSFUL:
            GPIO.setwarnings(False)
            GPIO.setmode(GPIO.BOARD)  # Broadcom pin-numbering scheme
        self.alaModeReconfig = False

        while setupSocket > 0:
            try:
                #multicast socket
                self.mcast = socket.socket(socket.AF_INET, socket.SOCK_DGRAM,
                                           socket.IPPROTO_UDP)
                self.mcast.setsockopt(socket.IPPROTO_IP,
                                      socket.IP_MULTICAST_LOOP, 1)

                mreq = struct.pack("4sl", socket.inet_aton(MCAST_GRP),
                                   socket.INADDR_ANY)
                self.mcast.setsockopt(socket.IPPROTO_IP,
                                      socket.IP_ADD_MEMBERSHIP, mreq)

                setupSocket = 0
            except socket.error as msg:
                setupSocket = setupSocket - 1
                log(msg.strerror + " - Sleeping to try again")
                time.sleep(MCAST_RETRY_SLEEP_SEC)

        if setupSocket == MCAST_RETRY_ATTEMPTS:
            log(str(setupSocket))
            log("FATAL: Unable to setup socket")
            quit()

        self.valvesState = []
        self.fanTimer = None
        self.valvePowerTimer = None
        if int(self.OPTION_USE_3_WIRE_VALVES) == 1:
            self.valvePowerTimer = Timer(OPTION_VALVEPOWERON,
                                         self.valveStopPower)

        self.updateFlowmeterConfig()
        self.updateValvePins()

        self.commandserver = CommandTCPServer(('localhost', MCAST_PORT),
                                              CommandTCPHandler)
        self.commandserver.pintdispatch = self
        self.fanControl = FanControlThread("fanControl1", self)
        self.flowmonitor = FlowMonitor(self)

    def parseConnFile(self):
        connFileName = ADMIN_INCLUDES_DIR + "/conn.php"
        connDict = dict()
        with open(connFileName) as connFile:
            for line in connFile:
                instructions = line.split(";")
                if (len(instructions) < 1):
                    continue
                php = instructions[0].strip()
                php = php.strip("$")
                keyValue = php.split("=")
                if (len(keyValue) != 2):
                    continue
                connDict[keyValue[0]] = keyValue[1].strip("\"")
        return connDict

    def connectDB(self):
        cp = self.parseConnFile()
        con = mdb.connect(cp['host'], cp['username'], cp['password'],
                          cp['db_name'])
        return con

    def getConfig(self):
        con = self.connectDB()
        cursor = con.cursor(mdb.cursors.DictCursor)
        cursor.execute("SELECT * from config")
        rows = cursor.fetchall()
        con.close()
        return rows

    def getConfigValueByName(self, name):
        con = self.connectDB()
        cursor = con.cursor(mdb.cursors.DictCursor)
        cursor.execute("SELECT configValue from config WHERE configName='" +
                       name + "'")
        rows = cursor.fetchall()
        con.close()
        if len(rows) == 0:
            return None
        return rows[0]['configValue']

    def getTapConfig(self):
        con = self.connectDB()
        cursor = con.cursor(mdb.cursors.DictCursor)
        cursor.execute(
            "SELECT tc.tapId,tc.flowPin,tc.valvePin,tc.valveOn FROM tapconfig tc LEFT JOIN taps t ON tc.tapId = t.id WHERE t.active = 1 ORDER BY tc.tapId"
        )
        rows = cursor.fetchall()
        con.close()
        return rows

    def getRFIDReaders(self):
        con = self.connectDB()
        cursor = con.cursor(mdb.cursors.DictCursor)
        cursor.execute("SELECT * from rfidReaders ORDER BY priority")
        rows = cursor.fetchall()
        con.close()
        return rows

    def getMotionDetectors(self):
        con = self.connectDB()
        cursor = con.cursor(mdb.cursors.DictCursor)
        cursor.execute("SELECT * from motionDetectors ORDER BY priority")
        rows = cursor.fetchall()
        con.close()
        return rows

    def getLoadCellConfig(self):
        con = self.connectDB()
        cursor = con.cursor(mdb.cursors.DictCursor)
        cursor.execute(
            "SELECT tapId,loadCellCmdPin,loadCellRspPin,loadCellUnit FROM tapconfig WHERE loadCellCmdPin IS NOT NULL ORDER BY tapId"
        )
        rows = cursor.fetchall()
        con.close()
        return rows

    def getTareRequest(self, tapId):
        con = self.connectDB()
        cursor = con.cursor(mdb.cursors.DictCursor)
        cursor.execute(
            "SELECT tapId,loadCellTareReq FROM tapconfig WHERE tapId = " +
            str(tapId))
        rows = cursor.fetchall()
        con.close()
        if len(rows) == 0:
            return False
        return rows[0]['loadCellTareReq'] == 1

    def setTareRequest(self, tapId, tareRequested):
        tareReq = "0"
        if tareRequested:
            tareReq = "1"
        sql = "UPDATE tapconfig SET loadCellTareReq=" + tareReq
        if not tareRequested:
            sql = sql + ",loadCellTareDate=NOW()"
        sql = sql + " WHERE tapId = " + str(tapId)
        con = self.connectDB()
        cursor = con.cursor(mdb.cursors.DictCursor)
        result = cursor.execute(sql)
        con.commit()
        con.close()

    def addTempProbeAsNeeded(self, probe):
        sql = "SELECT * FROM tempProbes WHERE name='" + probe + "';"
        con = self.connectDB()
        cursor = con.cursor(mdb.cursors.DictCursor)
        result = cursor.execute(sql)
        if (cursor.rowcount <= 0):
            cursor.execute("INSERT INTO tempProbes (name, type) VALUES('" +
                           probe + "', 0)")
        con.commit()
        con.close()

    def saveTemp(self, probe, temp, tempUnit):
        insertLogSql = "INSERT INTO tempLog (probe, temp, tempUnit, takenDate) "
        insertLogSql += "VALUES('" + probe + "'," + str(
            temp
        ) + "+ COALESCE((SELECT manualAdj FROM tempProbes WHERE name = '" + probe + "'), 0), '" + str(
            tempUnit) + "', NOW());"
        con = self.connectDB()
        cursor = con.cursor(mdb.cursors.DictCursor)
        result = cursor.execute(insertLogSql)
        con.commit()
        con.close()
        self.archiveTemp()

    def getTempProbeConfig(self):
        useTempProbes = self.getConfigValueByName("useTempProbes")
        if (useTempProbes is not None and int(useTempProbes) == 1):
            return True
        return False

    #set to -1 so on startup archive is checked
    lastArchiveCheck = -1

    #Combine all readings older than 2 months into 1 average for the month to reduce rows in the table
    def archiveTemp(self):
        #only archive if the month has changed
        if self.lastArchiveCheck == datetime.datetime.now().month:
            return
        insertLogSql = """INSERT INTO tempLog (takenDate, probe, temp, humidity) 
            (SELECT CAST(DATE_FORMAT(takenDate,'%Y-%m-01') as DATE), 'History', TRUNCATE(AVG(temp), 2), TRUNCATE(hl.humidity, 2) 
                FROM tempLog tl
                    LEFT JOIN (SELECT CAST(DATE_FORMAT(takenDate,'%Y-%m-01') AS DATE) as takenMonth, AVG(humidity) AS humidity
                                        FROM tempLog
                                        WHERE probe != 'History' AND humidity IS NOT NULL AND
                                                takenDate < CAST(DATE_FORMAT(NOW() ,'%Y-%m-01') as DATE) 
                                        GROUP BY MONTH(takenDate)) hl    ON CAST(DATE_FORMAT(tl.takenDate,'%Y-%m-01') as DATE) = hl.takenMonth
                WHERE probe != 'History' AND
                        takenDate < CAST(DATE_FORMAT(DATE_SUB(NOW(), INTERVAL 1 MONTH) ,'%Y-%m-01') as DATE) 
                GROUP BY MONTH(takenDate));"""
        deleteSQL = """DELETE FROM tempLog 
                WHERE probe != 'History' AND
                        takenDate < CAST(DATE_FORMAT(DATE_SUB(NOW(), INTERVAL 1 MONTH) ,'%Y-%m-01') as DATE) ;"""
        con = self.connectDB()
        cursor = con.cursor(mdb.cursors.DictCursor)
        result = cursor.execute(insertLogSql)
        result = cursor.execute(deleteSQL)
        con.commit()
        con.close()
        self.lastArchiveCheck = datetime.datetime.now().month

    def useFanControl(self):
        useFanControl = self.getConfigValueByName("useFanControl")
        if (useFanControl is None or int(useFanControl) == 0):
            return False
        return True

    def getFanPin(self):
        fanPin = self.getConfigValueByName("useFanPin")
        if fanPin is not None:
            return int(fanPin)
        return -1

    def getFanOnTime(self):
        fanPin = self.getConfigValueByName("fanOnTime")
        if fanPin is not None:
            return int(fanPin)
        return 0

    def getFanOffTime(self):
        fanPin = self.getConfigValueByName("fanInterval")
        if fanPin is not None:
            return int(fanPin)
        return 0

    # check if we're exceeding the pour threshold
    def sendflowupdate(self, pin, count):
        return

    # check if we're exceeding the pour threshold
    def sendkickupdate(self, pin):
        msg = "RPU:KICK:" + str(pin)
        debug("Kicking Keg: " + msg.rstrip())
        self.mcast.sendto(msg + "\n", (MCAST_GRP, MCAST_PORT))

    # send a mcast flow update
    def sendflowcount(self, rfid, pin, count):
        if self.OPTION_RESTART_FANTIMER_AFTER_POUR:
            self.fanControl.restartNeeded(True)
        msg = "RPU:FLOW:" + str(pin) + "=" + str(count) + ":" + rfid
        debug("count update: " + msg.rstrip())
        self.mcast.sendto(msg + "\n", (MCAST_GRP, MCAST_PORT))

    # send a mcast valve/pin update
    def sendvalveupdate(self, pin, value):
        msg = "RPU:VALVE:" + str(pin) + "=" + str(value)
        debug("valve update: " + msg.rstrip())
        self.mcast.sendto(msg + "\n", (MCAST_GRP, MCAST_PORT))

    # send a mcast fan update
    def sendfanupdate(self, pin, value):
        msg = "RPU:FAN:" + str(pin) + "=" + str(value)
        debug("fan update: " + msg.rstrip())
        self.mcast.sendto(msg + "\n", (MCAST_GRP, MCAST_PORT))

    # send a mcast fan update
    def sendconfigupdate(self, ):
        debug("config update: " + "RPU:CONFIG")
        self.mcast.sendto("RPU:CONFIG\n", (MCAST_GRP, MCAST_PORT))

    # start running the flow monitor in it's own thread
    def spawn_flowmonitor(self):
        while True:
            try:
                if (config['dispatch.debugMonitoring']):
                    self.flowmonitor.fakemonitor()
                else:
                    self.flowmonitor.monitor()
            except Exception, e:
                log("serial connection stopped...")
                debug(str(e))
            finally:
Exemplo n.º 3
0
class PintDispatch(object):
    
    def __init__(self):
        self.OPTION_USE_3_WIRE_VALVES = self.getConfigValueByName("use3WireValves")
        self.OPTION_RESTART_FANTIMER_AFTER_POUR = self.getConfigValueByName("restartFanAfterPour")
        setupSocket = MCAST_RETRY_ATTEMPTS
        if GPIO_IMPORT_SUCCESSFUL:
            GPIO.setwarnings(False)
            GPIO.setmode(GPIO.BOARD) # Broadcom pin-numbering scheme
        self.alaModeReconfig = False;

        while setupSocket > 0:
            try:
                #multicast socket
                self.mcast = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
                self.mcast.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_LOOP, 1)

                mreq = struct.pack("4sl", socket.inet_aton(MCAST_GRP), socket.INADDR_ANY)    
                self.mcast.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq)
                
                setupSocket = 0
            except socket.error as msg:
                setupSocket = setupSocket - 1
                log(msg.strerror + " - Sleeping to try again")
                time.sleep(MCAST_RETRY_SLEEP_SEC)
                        
        if setupSocket == MCAST_RETRY_ATTEMPTS:
            log(str(setupSocket))
            log("FATAL: Unable to setup socket")
            quit()
            
        self.valvesState = []
        self.fanTimer = None
        self.valvePowerTimer = None
        if int(self.OPTION_USE_3_WIRE_VALVES) == 1:
            self.valvePowerTimer = Timer(OPTION_VALVEPOWERON, self.valveStopPower)
    
        self.updateFlowmeterConfig()
        self.updateValvePins()
        
        self.commandserver = CommandTCPServer(('localhost', MCAST_PORT), CommandTCPHandler)
        self.commandserver.pintdispatch = self
        self.fanControl = FanControlThread("fanControl1", self)
        self.flowmonitor = FlowMonitor(self, Logger())
        
    def getConfig(self):
        con = connectDB()
        cursor = con.cursor(mdb.cursors.DictCursor)
        cursor.execute("SELECT * from config")
        rows = cursor.fetchall()
        con.close()
        return rows
    
    def getConfigValueByName(self, name):
        con = connectDB()
        cursor = con.cursor(mdb.cursors.DictCursor)
        cursor.execute("SELECT configValue from config WHERE configName='"+name+"'")
        rows = cursor.fetchall()
        con.close()
        if len(rows) == 0:
            return None
        return rows[0]['configValue']

    def getTapConfig(self):
        con = connectDB()
        cursor = con.cursor(mdb.cursors.DictCursor)
        cursor.execute("SELECT tc.tapId,tc.flowPin,tc.valvePin,tc.valveOn FROM tapconfig tc LEFT JOIN taps t ON tc.tapId = t.id WHERE t.active = 1 ORDER BY tc.tapId")
        rows = cursor.fetchall()
        con.close()
        return rows
    
    def getRFIDReaders(self):
        con = connectDB()
        cursor = con.cursor(mdb.cursors.DictCursor)
        cursor.execute("SELECT * from rfidReaders ORDER BY priority")
        rows = cursor.fetchall()
        con.close()
        return rows
    
    def getMotionDetectors(self):
        con = connectDB()
        cursor = con.cursor(mdb.cursors.DictCursor)
        cursor.execute("SELECT * from motionDetectors ORDER BY priority")
        rows = cursor.fetchall()
        con.close()
        return rows
    
    def getLoadCellConfig(self):
        con = connectDB()
        cursor = con.cursor(mdb.cursors.DictCursor)
        cursor.execute("SELECT tapId,loadCellCmdPin,loadCellRspPin,loadCellUnit,loadCellScaleRatio,loadCellTareOffset FROM tapconfig WHERE loadCellCmdPin IS NOT NULL ORDER BY tapId")
        rows = cursor.fetchall()
        con.close()
        return rows
    
    def getGasTankLoadCellConfig(self):
        con = connectDB()
        cursor = con.cursor(mdb.cursors.DictCursor)
        cursor.execute("SELECT id,loadCellCmdPin,loadCellRspPin,loadCellUnit,loadCellScaleRatio,loadCellTareOffset FROM gasTanks WHERE loadCellCmdPin IS NOT NULL ORDER BY id")
        rows = cursor.fetchall()
        con.close()
        return rows
    
    def getTareRequest(self, tapId):
        con = connectDB()
        cursor = con.cursor(mdb.cursors.DictCursor)
        cursor.execute("SELECT tapId,loadCellTareReq FROM tapconfig WHERE tapId = " + str(tapId))
        rows = cursor.fetchall()
        con.close()
        if len(rows) == 0:
            return False
        return rows[0]['loadCellTareReq'] == 1
    
    def setLoadCellTareOffset(self, tapId, offset):
        sql = "UPDATE tapconfig SET loadCellTareOffset="+str(offset)
        sql = sql + " WHERE tapId = " + str(tapId)
        con = connectDB()
        cursor = con.cursor(mdb.cursors.DictCursor)
        result = cursor.execute(sql)
        con.commit()
        con.close()
        
    def getGasTankTareRequest(self, id):
        con = connectDB()
        cursor = con.cursor(mdb.cursors.DictCursor)
        cursor.execute("SELECT id,loadCellTareReq FROM gasTanks WHERE id = " + str(id))
        rows = cursor.fetchall()
        con.close()
        if len(rows) == 0:
            return False
        return rows[0]['loadCellTareReq'] == 1
    
    def setGasTankTareRequest(self, id, tareRequested):
        tareReq = "0"
        if tareRequested:
            tareReq = "1"
        sql = "UPDATE gasTanks SET loadCellTareReq="+tareReq
        if not tareRequested:
            sql = sql + ",loadCellTareDate=NOW()"
        sql = sql + " WHERE id = " + str(id)
        con = connectDB()
        cursor = con.cursor(mdb.cursors.DictCursor)
        result = cursor.execute(sql)
        con.commit()
        con.close()
        
    def getiSpindelConnectors(self):
        con = connectDB()
        cursor = con.cursor(mdb.cursors.DictCursor)
        cursor.execute("SELECT * from iSpindel_Connector")
        rows = cursor.fetchall()
        con.close()
        return rows
    
    def getiSpindelDevice(self, id, token, name, gravity):
        self.addiSpindelDeviceAsNeeded(id, token, name, gravity)
        con = connectDB()
        cursor = con.cursor(mdb.cursors.DictCursor)
        cursor.execute("SELECT i.*, b.name AS beerName, COALESCE(bb.name,bb.batchNumber) as batchName from iSpindel_Device i LEFT JOIN beers b ON i.beerId = b.id LEFT JOIN beerBatches bb ON i.beerBatchId = bb.id WHERE iSpindelId = "+str(id))
        rows = cursor.fetchall()
        con.close()
        if(cursor.rowcount <= 0):
            return None
        else:
            return rows[0]

    def addiSpindelDeviceAsNeeded(self, id, token, name, gravity):
        sql = "SELECT * FROM iSpindel_Device WHERE iSpindelId='" + str(id) + "';"
        con = connectDB()
        cursor = con.cursor(mdb.cursors.DictCursor)
        result = cursor.execute(sql)
        rows = cursor.fetchall()
        if(cursor.rowcount <= 0):
            cursor.execute("INSERT INTO iSpindel_Device (iSpindelId, token, name, gravityUnit, createdDate) VALUES("+str(id)+",'"+str(token)+"','"+str(name)+"','"+("sg" if gravity<2 else "p")+"', NOW())")
        else:
            if(rows[0]['active'] == 0 or rows[0]['token'] != str(token) or rows[0]['name'] != str(name)) :
                updateCursor = con.cursor(mdb.cursors.DictCursor)
                updateCursor.execute("UPDATE iSpindel_Device SET active=1, token='"+str(token)+"', name ='"+name+"' WHERE iSpindelId ='" + str(id) + "'")           
        con.commit()
        con.close()
        
    def getiSpindelUnsentConfig(self, id):
        con = connectDB()
        cursor = con.cursor(mdb.cursors.DictCursor)
        cursor.execute("SELECT iSpindelId, `interval`, token, polynomial, sent from iSpindel_Device WHERE sent != TRUE AND iSpindelId = "+str(id))
        rows = cursor.fetchall()
        con.close()
        if(cursor.rowcount <= 0):
            return None
        else:
            return rows[0]
        
    def updateiSpindeConfigMarkSent(self, id):
        con = connectDB()
        cursor = con.cursor(mdb.cursors.DictCursor)
        cursor.execute("UPDATE iSpindel_Device SET sent = TRUE WHERE sent != TRUE AND iSpindelId = "+str(id))
        con.commit()
        con.close()
        
    def insertiSpindelData(self, fieldlist, valuelist):
        con = connectDB()
        cursor = con.cursor(mdb.cursors.DictCursor)
        #debug(str(fieldlist))
        #debug(str(valuelist))
        # gather the data now and send it to the database
        fieldstr = ', '.join(fieldlist)
        valuestr = ', '.join(['%s' for x in valuelist])
        add_sql = 'INSERT INTO iSpindel_Data (' + fieldstr + ')'
        add_sql += ' VALUES (' + valuestr + ')'
        #debug(add_sql)
        cursor.execute(add_sql, valuelist)
        con.commit()
        cursor.close()
        con.close()

    def setTareRequest(self, tapId, tareRequested):
        tareReq = "0"
        if tareRequested:
            tareReq = "1"
        sql = "UPDATE tapconfig SET loadCellTareReq="+tareReq
        if not tareRequested:
            sql = sql + ",loadCellTareDate=NOW()"
        sql = sql + " WHERE tapId = " + str(tapId)
        con = connectDB()
        cursor = con.cursor(mdb.cursors.DictCursor)
        result = cursor.execute(sql)
        con.commit()
        con.close()
        
    def addTempProbeAsNeeded(self, probe):
        state_pin = 0
        sql = "SELECT * FROM tempProbes WHERE name='"+probe+"';"
        con = connectDB()
        cursor = con.cursor(mdb.cursors.DictCursor)
        result = cursor.execute(sql)
        rows = cursor.fetchall()
        if(cursor.rowcount <= 0):
            cursor.execute("INSERT INTO tempProbes (name, type) VALUES('"+probe+"', 0)")
        else:
            if rows[0]['statePin'] != None:
                state_pin = int(rows[0]['statePin'])
            if(rows[0]['active'] == 0) :
                updateCursor = con.cursor(mdb.cursors.DictCursor)
                updateCursor.execute("UPDATE tempProbes SET active=1 WHERE name ='" + probe+"'")           
                    
        con.commit()
        con.close()        
        
        return state_pin
             
    def saveTemp(self, probe, temp, tempUnit, takenDate):
        insertLogSql = "INSERT INTO tempLog (probe, temp, tempUnit, takenDate) "
        insertLogSql += "VALUES('"+probe+"',"+str(temp)+"+ COALESCE((SELECT manualAdj FROM tempProbes WHERE name = '"+probe+"'), 0), '"+str(tempUnit)+"', '"+takenDate+"');"
        con = connectDB()
        cursor = con.cursor(mdb.cursors.DictCursor)
        result = cursor.execute(insertLogSql)
        con.commit()
        con.close()
        self.archiveTemp()
        
    def saveTemps(self, temps):
        con = connectDB()
        cursor = con.cursor(mdb.cursors.DictCursor)
        for temp in temps:
            insertLogSql = "INSERT INTO tempLog (probe, temp, tempUnit, takenDate, statePinState) "
            insertLogSql += "VALUES('"+temp[0]+"',"+str(temp[1])+"+ COALESCE((SELECT manualAdj FROM tempProbes WHERE name = '"+temp[0]+"'), 0), '"+str(temp[2])+"', '"+temp[3]+"',"
            insertLogSql += str(temp[4]) if temp[4] != None else "null"
            insertLogSql += ");"
            result = cursor.execute(insertLogSql)
        con.commit()
        con.close()
        self.archiveTemp()
        
    def getTempProbeConfig(self):
        useTempProbes = self.getConfigValueByName("useTempProbes")
        if(useTempProbes is not None and int(useTempProbes) == 1):
            return True
        return False  
    #set to -1 so on startup archive is checked
    lastArchiveCheck = -1
    #Combine all readings older than 2 months into 1 average for the month to reduce rows in the table
    def archiveTemp(self):
        #only archive if the month has changed
        if self.lastArchiveCheck == datetime.datetime.now().month:
            return
        insertLogSql = """INSERT INTO tempLog (takenDate, probe, temp, humidity) 
            (SELECT CAST(DATE_FORMAT(takenDate,'%Y-%m-01') as DATE), 'History', TRUNCATE(AVG(temp), 2), TRUNCATE(hl.humidity, 2) 
                FROM tempLog tl
                    LEFT JOIN (SELECT CAST(DATE_FORMAT(takenDate,'%Y-%m-01') AS DATE) as takenMonth, AVG(humidity) AS humidity
                                        FROM tempLog
                                        WHERE probe != 'History' AND humidity IS NOT NULL AND
                                                takenDate < CAST(DATE_FORMAT(NOW() ,'%Y-%m-01') as DATE) 
                                        GROUP BY MONTH(takenDate)) hl    ON CAST(DATE_FORMAT(tl.takenDate,'%Y-%m-01') as DATE) = hl.takenMonth
                WHERE probe != 'History' AND
                        takenDate < CAST(DATE_FORMAT(DATE_SUB(NOW(), INTERVAL 1 MONTH) ,'%Y-%m-01') as DATE) 
                GROUP BY MONTH(takenDate));"""
        deleteSQL = """DELETE FROM tempLog 
                WHERE probe != 'History' AND
                        takenDate < CAST(DATE_FORMAT(DATE_SUB(NOW(), INTERVAL 1 MONTH) ,'%Y-%m-01') as DATE) ;"""
        con = connectDB()
        cursor = con.cursor(mdb.cursors.DictCursor)
        result = cursor.execute(insertLogSql)
        result = cursor.execute(deleteSQL)
        con.commit()
        con.close()
        self.lastArchiveCheck = datetime.datetime.now().month
    
    def useFanControl(self):
        useFanControl = self.getConfigValueByName("useFanControl")
        if(useFanControl is None or int(useFanControl) == 0):
            return False
        return True    
            
    def getFanPin(self):
        fanPin = self.getConfigValueByName("useFanPin")
        if fanPin is not None:
            return int(fanPin)
        return -1
    def getFanOnTime(self):
        fanPin = self.getConfigValueByName("fanOnTime")
        if fanPin is not None:
            return int(fanPin)
        return 0
    def getFanOffTime(self):
        fanPin = self.getConfigValueByName("fanInterval")
        if fanPin is not None:
            return int(fanPin)
        return 0
    
    # check if we're exceeding the pour threshold
    def sendflowupdate(self, pin, count):
        return
        
    # check if we're exceeding the pour threshold
    def sendkickupdate(self, pin):
        msg = "RPU:KICK:" + str(pin)
        debug("Kicking Keg: "  + msg.rstrip())
        self.mcast.sendto(msg + "\n", (MCAST_GRP, MCAST_PORT))
            
    # send a mcast flow update
    def sendflowcount(self, rfid, pin, count):
        if self.OPTION_RESTART_FANTIMER_AFTER_POUR:
            self.fanControl.restartNeeded(True)
        msg = "RPU:FLOW:" + str(pin) + "=" + str(count) +":" + rfid
        debug("count update: "  + msg.rstrip())
        self.mcast.sendto(msg + "\n", (MCAST_GRP, MCAST_PORT))
        
    # send a mcast valve/pin update
    def sendvalveupdate(self, pin, value):
        msg = "RPU:VALVE:" + str(pin) + "=" + str(value)
        debug("valve update: "  + msg.rstrip())
        self.mcast.sendto(msg + "\n", (MCAST_GRP, MCAST_PORT))
        
    # send a mcast fan update
    def sendfanupdate(self, pin, value):
        msg = "RPU:FAN:" + str(pin) + "=" + str(value)
        debug("fan update: "  + msg.rstrip())
        self.mcast.sendto(msg + "\n", (MCAST_GRP, MCAST_PORT))
      
    # send a mcast fan update
    def sendconfigupdate(self,):
        debug("config update: "  +  "RPU:CONFIG")
        self.mcast.sendto("RPU:CONFIG\n", (MCAST_GRP, MCAST_PORT))
        
    # start running the flow monitor in it's own thread
    def spawn_flowmonitor(self):
        while True:
            try:
                if(config['dispatch.debugMonitoring']):
                    self.flowmonitor.fakemonitor()
                else:
                    self.flowmonitor.monitor(self.useOption("useFlowMeter"))
            except Exception as e:
                log("serial connection stopped...")
                debug( str(e) )
            finally:
                time.sleep(1)
                log("flowmonitor aborted, restarting...")
                

    def spawnWebSocketServer(self):
        args = ["-p", "8081", "-d", PYTHON_WSH_DIR]
        #only log all errors in the webservice if we are debuging, turn level to critical
        if(not config['dispatch.debug']):
            args.append("--log-level")
            args.append("critical")
        options, args = _parse_args_and_config(args=args)
        options.cgi_directories = []
        options.is_executable_method = None
        os.chdir(options.document_root)
        _configure_logging(options)        
        server = WebSocketServer(options)
        server.serve_forever()

    # main setup
    def setup(self):
        # need small delay to get logging going, otherwise first log entries are missing
        time.sleep(2)
        debug("starting setup...")
        self.flowmonitor.setup()
        
    # main start method
    def start(self):

        log("starting WS server")
        t = threading.Thread(target=self.spawnWebSocketServer)
        t.setDaemon(True)
        t.start()

        log("starting device monitors...")
        t = threading.Thread(target=self.spawn_flowmonitor)
        t.setDaemon(True)
        t.start()
            
        log("starting command server")
        t = threading.Thread(target=self.commandserver.serve_forever)
        t.setDaemon(True)
        t.start()
        
        log("starting fan control")
        self.fanControl.start()
        
        signal.pause()
        debug( "exiting...")
        
    # 
    def triggerAlaModeReset(self):
        self.alaModeReconfig = True;
        
    # check if something got changed which requires reset/reconfigure of alamode
    def needAlaModeReconfig(self):
        return 1 if self.alaModeReconfig else 0
                    
    # reset the alamode by tripping it's reset line
    def resetAlaMode(self):
        self.alaModeReconfig = False;
        resetpin = 12

        if GPIO_IMPORT_SUCCESSFUL:
            GPIO.setup(int(resetpin), GPIO.OUT)
            oldValue = GPIO.input(resetpin)
            if (oldValue == 1):
                value1 = 0
            else:
                value1 = 1
                
            self.updatepin(resetpin, value1)
            time.sleep(1)
            self.updatepin(resetpin, oldValue)
            
            self.OPTION_RESTART_FANTIMER_AFTER_POUR = self.getConfigValueByName("restartFanAfterPour")
        
    # update PI gpio pin mode (either input or output), this requires that this is run as root 
    def setpinmode(self, pin, value):
        if not GPIO_IMPORT_SUCCESSFUL:
            return False
        
        if (pin < 1):
            debug("invalid pin " + str(pin))
            return False
        
            debug( "update pin MODE %s to %s" %(pin, value))
            if int(value) == 0 :
                    GPIO.setup(int(pin), GPIO.IN)
            else:
                    GPIO.setup(int(pin), GPIO.OUT)
            return True
        
    # update PI gpio pin (either turn on or off), this requires that this is run as root 
    def updatepin(self, pin, value):
        if not GPIO_IMPORT_SUCCESSFUL:
            return False
        
        pin = int(pin)
        value = int(value)
        if (pin < 1):
            debug("invalid pin " + str(pin))
            return False
        
        GPIO.setup(pin, GPIO.OUT)
        oldValue = GPIO.input(pin)
        if(oldValue != value):
            #debug( "update pin %s from %s to %s" %(pin, oldValue, value))
            if value == 0 :
                GPIO.output(pin, GPIO.LOW)
            else:
                GPIO.output(pin, GPIO.HIGH)
                
            sql = "UPDATE tapconfig SET valvePinState=" + str(value) + " WHERE valvePin =" +  str(-1*pin)
            con = connectDB()
            cursor = con.cursor(mdb.cursors.DictCursor)
            result = cursor.execute(sql)
            con.commit()
            con.close()
            
            return True
        return False

    # update PI gpio pin (either turn on or off), this requires that this is run as root 
    def readpin(self, pin):
        if not GPIO_IMPORT_SUCCESSFUL:
            return 0
        pin = int(pin)
        if (pin < 1):
            debug("invalid pin " + str(pin))
            return 0
        value = GPIO.input(pin)
        debug( "read pin %s value %s" %(pin, value))
        return value;
                
    def valveStopPower(self):
        debug( "stopping valve power on pin %s" %(OPTION_VALVEPOWERPIN))
        self.updatepin(self.getValvesPowerPin(), 0)
        
    def updateValvePins(self):            
        taps = self.getTapConfig()
        ii = 0
        for tap in taps:
            if( len(self.valvesState) < ii + 1):
                self.valvesState.append(-1)
                
            if(tap["valveOn"] is None):
                tap["valveOn"] = 0
                
            if self.valvesState[ii] != int(tap["valveOn"]):
                self.sendvalveupdate(ii, tap["valveOn"])
                
            self.valvesState[ii] = int(tap["valveOn"])
            ii = ii + 1
            
    def getValvesState(self):
        return self.valvesState      
    
    def getConfigItem(self, itemName):
        config = self.getConfig()
        for item in config:
            if (item["configName"] == itemName):
                return item
        return None
           
    def updateFlowmeterConfig(self):            
        pourShutOffCountItem = self.getConfigItem("pourShutOffCount")
        if(pourShutOffCountItem is None):
            self.pourShutOffCount = 0;
        else:
            self.pourShutOffCount = int(pourShutOffCountItem["configValue"])

    
    def useOption(self, option):
        cfItem = self.getConfigItem(option)
        if cfItem is None:
            return False
        cfUse = cfItem["configValue"]
        if(int(cfUse) == 1):
            return True
        return False
            
    def getValvesPowerPin(self):
        if self.useOption("useTapValves"):
            valveItem = self.getConfigItem("valvesPowerPin")
            if valveItem is not None:
                return int(valveItem["configValue"])
        return -1
        
    def getValvesPowerTime(self):
        if self.useOption("useTapValves"):
            valveItem = self.getConfigItem("valvesOnTime")
            if valveItem is not None:
                return int(valveItem["configValue"])
        return -1
        
    def shutdown(self,):
        log("Shuting Down System")
        os.system('sudo shutdown -P now')
    
    def restart(self,):
        log("Rebooting System")
        os.system('sudo reboot')
        
    def restartService(self,):
        log("Restarting Service")
        os.system('sudo /etc/init.d/flowmon restart')
        
    def upgrade(self,varient="", branch_to_use="", tag=""):
        log("Upgrading RPints Service")
        
        cmds = {}
        if varient == "":
            subprocess.call(""+PINTS_DIR+"/util/installRaspberryPints --u --i "+PINTS_DIR, shell=True)

        elif varient == "force":
            subprocess.call(""+PINTS_DIR+"/util/installRaspberryPints --u --f --i "+PINTS_DIR, shell=True)

    # send a mcast refresh update
    def refreshWebpages(self):
        debug("config update: REFRESH")
        self.mcast.sendto("RPU:REFRESH\n", (MCAST_GRP, MCAST_PORT))