Created
December 5, 2017 03:32
-
-
Save craigjmidwinter/1b215c680b0179d50c0f8f54c5e29510 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
Support for Dominos Pizza ordering. | |
The Dominos Pizza component ceates a service which can be invoked to order | |
from their menu | |
For more details about this platform, please refer to the documentation at | |
https://home-assistant.io/components/dominos/. | |
""" | |
import logging | |
from datetime import timedelta | |
import voluptuous as vol | |
import homeassistant.helpers.config_validation as cv | |
from homeassistant.components import http | |
from homeassistant.core import callback | |
from homeassistant.helpers.entity import Entity | |
from homeassistant.helpers.entity_component import EntityComponent | |
from homeassistant.util import Throttle | |
_LOGGER = logging.getLogger(__name__) | |
# The domain of your component. Should be equal to the name of your component. | |
DOMAIN = 'dominos' | |
ENTITY_ID_FORMAT = DOMAIN + '.{}' | |
ATTR_COUNTRY = 'country_code' | |
ATTR_FIRST_NAME = 'first_name' | |
ATTR_LAST_NAME = 'last_name' | |
ATTR_EMAIL = 'email' | |
ATTR_PHONE = 'phone' | |
ATTR_ADDRESS = 'address' | |
ATTR_ORDERS = 'orders' | |
ATTR_SHOW_MENU = 'show_menu' | |
ATTR_ORDER_ENTITY = 'order_entity_id' | |
ATTR_ORDER_NAME = 'name' | |
ATTR_ORDER_CODES = 'codes' | |
MIN_TIME_BETWEEN_UPDATES = timedelta(minutes=10) | |
MIN_TIME_BETWEEN_STORE_UPDATES = timedelta(minutes=3330) | |
REQUIREMENTS = ['pizzapi==0.0.3'] | |
DEPENDENCIES = ['http'] | |
_ORDERS_SCHEMA = vol.Schema({ | |
vol.Required(ATTR_ORDER_NAME): cv.string, | |
vol.Required(ATTR_ORDER_CODES): vol.All(cv.ensure_list, [cv.string]), | |
}) | |
CONFIG_SCHEMA = vol.Schema({ | |
DOMAIN: vol.Schema({ | |
vol.Required(ATTR_COUNTRY): cv.string, | |
vol.Required(ATTR_FIRST_NAME): cv.string, | |
vol.Required(ATTR_LAST_NAME): cv.string, | |
vol.Required(ATTR_EMAIL): cv.string, | |
vol.Required(ATTR_PHONE): cv.string, | |
vol.Required(ATTR_ADDRESS): cv.string, | |
vol.Optional(ATTR_SHOW_MENU): cv.boolean, | |
vol.Optional(ATTR_ORDERS, default=[]): vol.All( | |
cv.ensure_list, [_ORDERS_SCHEMA]), | |
}), | |
}, extra=vol.ALLOW_EXTRA) | |
def setup(hass, config): | |
"""Set up is called when Home Assistant is loading our component.""" | |
dominos = Dominos(hass, config) | |
component = EntityComponent(_LOGGER, DOMAIN, hass) | |
hass.data[DOMAIN] = {} | |
entities = [] | |
conf = config[DOMAIN] | |
hass.services.register(DOMAIN, 'order', dominos.handle_order) | |
if conf.get(ATTR_SHOW_MENU): | |
hass.http.register_view(DominosProductListView(dominos)) | |
for order_info in conf.get(ATTR_ORDERS): | |
order = DominosOrder(order_info, dominos) | |
entities.append(order) | |
if entities: | |
component.add_entities(entities) | |
# Return boolean to indicate that initialization was successfully. | |
return True | |
class Dominos(): | |
"""Main Dominos service.""" | |
def __init__(self, hass, config): | |
"""Set up main service.""" | |
conf = config[DOMAIN] | |
from pizzapi import Address, Customer | |
from pizzapi.address import StoreException | |
self.hass = hass | |
self.customer = Customer( | |
conf.get(ATTR_FIRST_NAME), | |
conf.get(ATTR_LAST_NAME), | |
conf.get(ATTR_EMAIL), | |
conf.get(ATTR_PHONE), | |
conf.get(ATTR_ADDRESS)) | |
self.address = Address( | |
*self.customer.address.split(','), | |
country=conf.get(ATTR_COUNTRY)) | |
self.country = conf.get(ATTR_COUNTRY) | |
try: | |
self.closest_store = self.address.closest_store() | |
except StoreException: | |
self.closest_store = None | |
def handle_order(self, call): | |
"""Handle ordering pizza.""" | |
entity_ids = call.data.get(ATTR_ORDER_ENTITY, None) | |
target_orders = [order for order in self.hass.data[DOMAIN]['entities'] | |
if order.entity_id in entity_ids] | |
for order in target_orders: | |
order.place() | |
@Throttle(MIN_TIME_BETWEEN_STORE_UPDATES) | |
def update_closest_store(self): | |
"""Update the shared closest store (if open).""" | |
from pizzapi.address import StoreException | |
try: | |
self.closest_store = self.address.closest_store() | |
return True | |
except StoreException: | |
self.closest_store = None | |
return False | |
def get_menu(self): | |
"""Return the products from the closest stores menu.""" | |
self.update_closest_store() | |
if self.closest_store is None: | |
_LOGGER.warning('Cannot get menu. Store may be closed') | |
return [] | |
else: | |
menu = self.closest_store.get_menu() | |
product_entries = [] | |
for product in menu.products: | |
item = {} | |
if isinstance(product.menu_data['Variants'], list): | |
variants = ', '.join(product.menu_data['Variants']) | |
else: | |
variants = product.menu_data['Variants'] | |
item['name'] = product.name | |
item['variants'] = variants | |
product_entries.append(item) | |
return product_entries | |
class DominosProductListView(http.HomeAssistantView): | |
"""View to retrieve product list content.""" | |
url = '/api/dominos' | |
name = "api:dominos" | |
def __init__(self, dominos): | |
"""Initialize suite view.""" | |
self.dominos = dominos | |
@callback | |
def get(self, request): | |
"""Retrieve if API is running.""" | |
menu = self.dominos.get_menu() | |
return self.json(menu) | |
class DominosOrder(Entity): | |
"""Represents a Dominos order entity.""" | |
def __init__(self, order_info, dominos): | |
"""Set up the entity.""" | |
self._name = order_info['name'] | |
self._product_codes = order_info['codes'] | |
self._orderable = False | |
self.dominos = dominos | |
@property | |
def name(self): | |
"""Return the orders name.""" | |
return self._name | |
@property | |
def product_codes(self): | |
"""Return the orders product codes.""" | |
return self._product_codes | |
@property | |
def orderable(self): | |
"""Return the true if orderable.""" | |
return self._orderable | |
@property | |
def state(self): | |
"""Return the state either closed, orderable or unorderable.""" | |
if self.dominos.closest_store is None: | |
return 'closed' | |
else: | |
return 'orderable' if self._orderable else 'unorderable' | |
@Throttle(MIN_TIME_BETWEEN_UPDATES) | |
def update(self): | |
"""Update the order state and refreshes the store.""" | |
from pizzapi.address import StoreException | |
try: | |
self.dominos.update_closest_store() | |
except StoreException: | |
self._orderable = False | |
return | |
try: | |
order = self.order() | |
order.pay_with() | |
self._orderable = True | |
except StoreException: | |
self._orderable = False | |
def order(self): | |
"""Create the order object.""" | |
from pizzapi import Order | |
from pizzapi.address import StoreException | |
if self.dominos.closest_store is None: | |
raise StoreException | |
order = Order( | |
self.dominos.closest_store, | |
self.dominos.customer, | |
self.dominos.address, | |
self.dominos.country) | |
for code in self._product_codes: | |
order.add_item(code) | |
return order | |
def place(self): | |
"""Place the order.""" | |
from pizzapi.address import StoreException | |
try: | |
order = self.order() | |
order.place() | |
except StoreException: | |
self._orderable = False | |
_LOGGER.warning( | |
'Attempted to order Dominos - Order invalid or store closed') |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment