Source code for senseo_api.pisenseo

#!/usr/bin/env python

import os
import json
from time import sleep
from RPi import GPIO


import logging
logger = logging.getLogger(__name__)

MAX_READY_RETRY = 60
PRESS_DELAY = 1
WAIT_RETRY = 0.5
# Disable warnings
GPIO.setwarnings(False)
# Working with GPIO Numbers
GPIO.setmode(GPIO.BCM)


[docs]class SenseoPreconditionError(Exception): """Define a specific error for non-readyness coffee machine. """ def __init__(self, message: str): """Initialize the execption. Args: message (str): Message to raise with error. """ self.message = message # Call the base class constructor with the parameters it needs super(SenseoPreconditionError, self).__init__(message) logger.error(f"[{self.__class__.__name__}] {message}")
[docs]class SenseoCoffeeSizeError(Exception): """Define a specific error for invalid coffee size. """ def __init__(self, size): """Initialize the execption. Args: message (str): Message to raise with error. """ self.message = f"Invalid coffee size requested: {size}. Only 1 or 2 are accepted." # Call the base class constructor with the parameters it needs super(SenseoCoffeeSizeError, self).__init__(self.message) logger.error(f"[{self.__class__.__name__}] {self.message}")
[docs]class SenseoClassic(): """Define the setup and methods for the Senseo Classic. May works on other kind of Senseo machine but not tested. """ def __init__(self, config_file: str): """Initialize the SenseoClassic object. Args: config_file (str): Path to the json config file. """ with open(os.path.expanduser(config_file), "r", encoding="utf-8") as fd: self.gpio_setup = json.load(fd) # Map GPIO pin configuration for in/out self.power_button = self.gpio_setup.get('power_button') logger.trivia(f"power_button pin is n°{self.power_button}") self.one_mug_button = self.gpio_setup.get('1_mug_button') logger.trivia(f"one_mug_button pin is n°{self.one_mug_button}") self.double_mug_button = self.gpio_setup.get('2_mug_button') logger.trivia(f"double_mug_button pin is n°{self.double_mug_button}") self.led = self.gpio_setup.get('led') logger.trivia(f"led pin is n°{self.led}") # PIN setup GPIO.setup(self.power_button, GPIO.OUT) GPIO.setup(self.one_mug_button, GPIO.OUT) GPIO.setup(self.double_mug_button, GPIO.OUT) GPIO.setup(self.led, GPIO.IN, pull_up_down=GPIO.PUD_UP) # Default state is HIGH everywhere (unpressed for buttons) GPIO.output(self.power_button, GPIO.HIGH) GPIO.output(self.one_mug_button, GPIO.HIGH) GPIO.output(self.double_mug_button, GPIO.HIGH) logger.info("Coffee machine setup is ready")
[docs] def is_led_on(self): """Return a boolean according to the current led status. Returns: Boolean: led powered status """ return bool(GPIO.input(self.led))
[docs] def is_powered_on(self): """Is the Senseo up? Returns: Boolean: Power status of the Senseo """ logger.debug("Checking power status of coffee machine") for i in range(0,10): # retest few times is_on = self.is_led_on() logger.debug(f"Current value for LED is: {is_on}") if is_on: logger.info("Coffee machine is powered on") return True logger.debug("Need to retry the power status check") sleep(WAIT_RETRY) # wait between two retries # LED is not powered on since a few seconds, let consider coffee machine is down logger.info("Coffee machine is powered off") return False
[docs] def is_ready(self): """Is the Senseo heat enough? Returns: Boolean: Heat status of the Senseo """ logger.debug("Checking readyness of coffee machine") for i in range(0,10): # retest few times is_on = self.is_led_on() logger.debug(f"Current value for LED is: {is_on}") if is_on: logger.debug("Need to retry check for readyness") else: # At lest the coffee machine is still heating logger.info("Coffee machine is not ready.") return False sleep(WAIT_RETRY) # wait a second before next try # LED is powered on since a few seconds, let consider ready. logger.info("Coffee machine is ready") return True
[docs] def single_press(self, button: int): """Press a specific button for a short period. Args: button (int): Button to press """ logger.info(f"Pressing a button for {PRESS_DELAY}s.") GPIO.output(button, GPIO.LOW) # press button sleep(PRESS_DELAY) GPIO.output(button, GPIO.HIGH) # unpress logger.debug(f"Button was successfully pressed.")
[docs] def start(self): """Power on the Senseo. """ logger.debug("Powering on is requested") if not self.is_powered_on(): logger.info("Pressing power button to startup.") self.single_press(self.power_button) return
[docs] def stop(self): """Power off the Senseo. """ logger.debug("Powering off is requested") if self.is_powered_on(): logger.info("Pressing power button to shutdown.") self.single_press(self.power_button) return
[docs] def coffee(self, size: int): """Start a coffee run according the selected number of mugs. Args: size (integer): Number of mug selected. 1 or 2. """ if size not in [1,2]: raise SenseoCoffeeSizeError(size) if size == 1: logger.debug("1 mugs coffee size requested") coffee_button = self.one_mug_button if size == 2: logger.debug("2 mug coffee size requested") coffee_button = self.double_mug_button # Test if coffee machine is ready if not self.is_powered_on(): logger.error("Coffee machine is not on: aborting.") raise SenseoPreconditionError("Coffe machine is not on: aborting.") if not self.is_ready(): logger.error("Coffe machine is not ready: aborting.") raise SenseoPreconditionError("Coffe machine is not ready: aborting.") # Press appropriate button for a short time logger.info("Requesting coffee run.") self.single_press(coffee_button) return