Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Dominos Pizza platform #10379

Merged
merged 37 commits into from
Nov 24, 2017
Merged
Show file tree
Hide file tree
Changes from 35 commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
3bca66e
add dominos service
craigjmidwinter Oct 20, 2017
b4c34c2
change require
craigjmidwinter Oct 26, 2017
6a3813b
Merge branch 'dev' of https://github.com/home-assistant/home-assistan…
craigjmidwinter Oct 30, 2017
4faf97d
dump to log
craigjmidwinter Nov 3, 2017
64adc01
component fixes
craigjmidwinter Nov 4, 2017
27d63a9
clean-up use updated library
craigjmidwinter Nov 4, 2017
b536647
remove unnecessary import
craigjmidwinter Nov 4, 2017
18bbbca
fix hound errors
craigjmidwinter Nov 5, 2017
2793808
more lint fixes
craigjmidwinter Nov 5, 2017
a1ba981
Coverage rc
craigjmidwinter Nov 5, 2017
2b9749f
Merge branch 'dev' of https://github.com/home-assistant/home-assistan…
craigjmidwinter Nov 5, 2017
456a1c4
update requirements
craigjmidwinter Nov 5, 2017
fe574e6
cleanup as per notes
craigjmidwinter Nov 7, 2017
03ad3ac
missing message
craigjmidwinter Nov 7, 2017
646cebc
linting...
craigjmidwinter Nov 7, 2017
c5f70d2
schema validation and reducing requests
craigjmidwinter Nov 7, 2017
fd90800
Merge branch 'dev' of https://github.com/home-assistant/home-assistan…
craigjmidwinter Nov 7, 2017
c59fe34
fixlint
craigjmidwinter Nov 7, 2017
bd1f914
spacing
craigjmidwinter Nov 7, 2017
7838ceb
unused variable
craigjmidwinter Nov 7, 2017
f0d70ae
fix docstrings
craigjmidwinter Nov 7, 2017
a6c0ca6
update req
craigjmidwinter Nov 8, 2017
cffcd13
notes updates, pypi package, front-end panel
craigjmidwinter Nov 12, 2017
53f4acc
stale import
craigjmidwinter Nov 12, 2017
33e6062
fix constant name
craigjmidwinter Nov 12, 2017
db75ffb
docstrings
craigjmidwinter Nov 12, 2017
ca1a115
fix library import
craigjmidwinter Nov 12, 2017
28542ae
lint fixes
craigjmidwinter Nov 12, 2017
3172f43
pylint bug
craigjmidwinter Nov 12, 2017
fc9808d
remove built-in panel
craigjmidwinter Nov 15, 2017
810a248
Make synchronous
craigjmidwinter Nov 16, 2017
6c049cb
unused import and use throttle
craigjmidwinter Nov 16, 2017
b9815f1
Handle exceptions properly and update client
craigjmidwinter Nov 16, 2017
483934d
Import exceptions properly
craigjmidwinter Nov 16, 2017
81f7d10
unused import
craigjmidwinter Nov 16, 2017
0c1c81e
remove bloat from start-up, readability fixes from notes, retrieve me…
craigjmidwinter Nov 24, 2017
c91b719
whitespace on blank line
craigjmidwinter Nov 24, 2017
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .coveragerc
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ omit =
homeassistant/components/digital_ocean.py
homeassistant/components/*/digital_ocean.py

homeassistant/components/dominos.py

homeassistant/components/doorbird.py
homeassistant/components/*/doorbird.py

Expand Down Expand Up @@ -632,7 +634,6 @@ omit =
homeassistant/components/zwave/util.py
homeassistant/components/vacuum/mqtt.py


[report]
# Regexes for lines to exclude from consideration
exclude_lines =
Expand Down
234 changes: 234 additions & 0 deletions homeassistant/components/dominos.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,234 @@
"""
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

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

'homeassistant.helpers.entity.Entity' imported but unused

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): 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 = []

hass.services.register(DOMAIN, 'order', dominos.handle_order)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add a schema for validating the service data.


if config[DOMAIN].get(ATTR_SHOW_MENU):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You keep doing config[DOMAIN] everywhere. May I suggest a conf = config[DOMAIN] at the top

dominos.show_menu(hass)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do this on startup instead of when it is called? That is slowing down the startup of Home Assistant unnecessarily.

hass.http.register_view(DominosProductListView)

for order_info in config[DOMAIN].get(ATTR_ORDERS):
order = DominosOrder(order_info, dominos)
entities.append(order)

component.add_entities(entities)

# Return boolean to indicate that initialization was successfully.
return True


class Dominos():

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

expected 2 blank lines, found 1

"""Main Dominos service."""

def __init__(self, hass, config):
"""Set up main service."""
from pizzapi import Address, Customer, Store
self.hass = hass
self.customer = Customer(
config[DOMAIN].get(ATTR_FIRST_NAME),
config[DOMAIN].get(ATTR_LAST_NAME),
config[DOMAIN].get(ATTR_EMAIL),
config[DOMAIN].get(ATTR_PHONE),
config[DOMAIN].get(ATTR_ADDRESS))
self.address = Address(
*self.customer.address.split(','),
country=config[DOMAIN].get(ATTR_COUNTRY))
self.country = config[DOMAIN].get(ATTR_COUNTRY)
self.closest_store = Store()
self.update_closest_store()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't seem to be async, yet you're calling it from an async context.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why would you do this on startup? It's already done when the entities are updated


def handle_order(self, call):
"""Handle ordering pizza."""
entity_ids = call.data.get(ATTR_ORDER_ENTITY, None)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

call can be None but you don't assume it's None in your code?


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()
except StoreException:
self.closest_store = False

def show_menu(self, hass):
"""Dump the closest stores menu into the logs."""
if self.closest_store is False:
_LOGGER.warning('Cannot get menu. Store may be closed')
return

menu = self.closest_store.get_menu()
hass.data[DOMAIN]['products'] = []

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
hass.data[DOMAIN]['products'].append(item)


class DominosProductListView(http.HomeAssistantView):
"""View to retrieve product list content."""

url = '/api/dominos'
name = "api:dominos"

@callback
def get(self, request):
"""Retrieve if API is running."""
return self.json(request.app['hass'].data[DOMAIN]['products'])


class DominosOrder(Entity):

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

expected 2 blank lines, found 1

"""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 False:
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
order = Order(

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

undefined name '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:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might want to create a persistent notification when this happens?

self._orderable = False
_LOGGER.warning(
'Attempted to order Dominos - Order invalid or store closed')
3 changes: 3 additions & 0 deletions requirements_all.txt
Original file line number Diff line number Diff line change
Expand Up @@ -540,6 +540,9 @@ piglow==1.2.4
# homeassistant.components.pilight
pilight==0.1.1

# homeassistant.components.dominos
pizzapi==0.0.3

# homeassistant.components.media_player.plex
# homeassistant.components.sensor.plex
plexapi==3.0.3
Expand Down