Esempio n. 1
0
 def __init__(self, reactor, config):
     self.reactor = reactor
     self.config = config
     self.history = TreatHistory(self.config.historyFile)
     self.lcd = SerialLCD(self.config.lcdBaud)
     self.lcd.clear()
     self.lcd.writeBothLines("")
     self.lcd.clear()
     self.lcd.enableBacklight(False)
     self.lcd.setDisplayMode(display = True, cursor = False, blink = False)
     self.gpio = GPIO()
     self.gpio.setupPin(self.config.gpioTreatDetector, GPIO.IN)
     self.gpio.setupPin(self.config.gpioButton, GPIO.IN)
     self.gpio.setupPin(self.config.gpioTreatPower, GPIO.OUT, 0)
     self.currentState = None
     self.lastState = None
     self.lastButtonState = False
     self.lastTreatDetectorState = False
Esempio n. 2
0
class TreatMachine:

    gpio = None

    def __init__(self, reactor, config):
        self.reactor = reactor
        self.config = config
        self.history = TreatHistory(self.config.historyFile)
        self.lcd = SerialLCD(self.config.lcdBaud)
        self.lcd.clear()
        self.lcd.writeBothLines("")
        self.lcd.clear()
        self.lcd.enableBacklight(False)
        self.lcd.setDisplayMode(display = True, cursor = False, blink = False)
        self.gpio = GPIO()
        self.gpio.setupPin(self.config.gpioTreatDetector, GPIO.IN)
        self.gpio.setupPin(self.config.gpioButton, GPIO.IN)
        self.gpio.setupPin(self.config.gpioTreatPower, GPIO.OUT, 0)
        self.currentState = None
        self.lastState = None
        self.lastButtonState = False
        self.lastTreatDetectorState = False

    def __del__(self):
        self.close()

    def __enter__(self):
        return self

    def __exit__(self, type, value, traceback):
        self.close()
        return False

    def close(self):
        self.gpio.close()
        self.lcd.close()

    def __str__(self):
        return "TreatMachine"

    def stop(self):
        if not self.currentState:
            return
        LOGGER.info("TreatMachine stopping")
        self.changeState(None)
        self.setTreatDispenserPowerState(False)
        self.lcd.writeBothLines("Treater disabled")
        self.lcd.enableBacklight(False)

    def start(self):
        if self.currentState:
            return
        LOGGER.info("TreatMachine starting")
        self.lastButtonState = False
        self.changeState(IdleState())
        self.run()

    def run(self):
        if not self.currentState:
            return

        callbackInterval = self.config.buttonPollSeconds

        try:
            # Fire treat detector event
            newTreatDetectorState = self.isTreatDetectorActive()
            if newTreatDetectorState != self.lastTreatDetectorState:
                if newTreatDetectorState:
                    self.currentState.onTreatDetected(self)
                self.lastTreatDetectorState = newTreatDetectorState

            # Fire button events
            newButtonState = self.isButtonPressed() 
            if newButtonState != self.lastButtonState:
                if newButtonState:
                    LOGGER.debug("Button pressed")
                    self.currentState.onButtonPressed(self)
                else:    
                    LOGGER.debug("Button released")
                    self.currentState.onButtonReleased(self)
                self.lastButtonState = newButtonState

            # Fire timer event
            if (self.currentState):
                self.currentState.onTimerTick(self)

            if (self.currentState ):
                callbackInterval = self.currentState.pollIntervalSeconds(self)

        except Exception as e:
            LOGGER.exception(e)
        finally:
            # Queue continual callback to service state machine
            self.reactor.callLater(callbackInterval, self.run)

    def changeState(self, newState):
        self.lastState = self.currentState
        self.currentState = newState
        LOGGER.debug("Changing states, %s -> %s" % (self.lastState, self.currentState) )
        if self.currentState is not None:
            self.currentState.enterState(self)

    def getCurrentStateName(self):
        if self.currentState is None:
            return "NotRunning"
        return str(self.currentState)

    def dispenseTreat(self):
        if self.currentState is not None:
            self.currentState.onTreatDispenseRequest(self)
        return isinstance(self.currentState, DispensingState)

    def isTreatDetectorActive(self):
        return self.gpio.readPin(self.config.gpioTreatDetector) != 0

    def isButtonPressed(self):
        return self.gpio.readPin(self.config.gpioButton) == 0

    def setTreatDispenserPowerState(self, enabled):
        if enabled:
            self.gpio.writePin(self.config.gpioTreatPower, 1)
        else:
            self.gpio.writePin(self.config.gpioTreatPower, 0)

    def updateLcdTreatStats(self, forceUpdate=False):
        now = datetime.now()
        try:
            if not forceUpdate and self.lastUpdateTime is not None and (now - self.lastUpdateTime) < timedelta(minutes=1):
                return
        except AttributeError:
            pass
        self.lastUpdateTime = now
        (cycleCount, treatCount, lastTreatTime)  = self.history.getTreatStats()
        line1 = "Treats : %d/%d" % (treatCount, cycleCount)
        if lastTreatTime is None:
            line2 = "Last   : > 24h"
        else:
            td = now - lastTreatTime
            line2 = "Last   : %dh %dm" % (td.days * 24 + td.seconds / 3600, (td.seconds % 3600) / 60)
        self.lcd.writeBothLines(line1, line2)