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
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)