Skip to content

Commit

Permalink
Fix stuff for async http
Browse files Browse the repository at this point in the history
  • Loading branch information
balloob committed Oct 18, 2016
1 parent 862deb6 commit 4615816
Show file tree
Hide file tree
Showing 10 changed files with 191 additions and 132 deletions.
28 changes: 16 additions & 12 deletions homeassistant/components/alexa.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
For more details about this component, please refer to the documentation at
https://home-assistant.io/components/alexa/
"""
import asyncio
import copy
import enum
import logging
Expand All @@ -12,6 +13,7 @@

import voluptuous as vol

from homeassistant.core import callback
from homeassistant.const import HTTP_BAD_REQUEST
from homeassistant.helpers import template, script, config_validation as cv
from homeassistant.components.http import HomeAssistantView
Expand All @@ -20,7 +22,7 @@
_LOGGER = logging.getLogger(__name__)

INTENTS_API_ENDPOINT = '/api/alexa'
FLASH_BRIEFINGS_API_ENDPOINT = '/api/alexa/flash_briefings/<briefing_id>'
FLASH_BRIEFINGS_API_ENDPOINT = '/api/alexa/flash_briefings/{briefing_id}'

CONF_ACTION = 'action'
CONF_CARD = 'card'
Expand Down Expand Up @@ -128,9 +130,10 @@ def __init__(self, hass, intents):

self.intents = intents

@asyncio.coroutine
def post(self, request):
"""Handle Alexa."""
data = request.json
data = yield from request.json()

_LOGGER.debug('Received Alexa request: %s', data)

Expand Down Expand Up @@ -176,7 +179,7 @@ def post(self, request):
action = config.get(CONF_ACTION)

if action is not None:
action.run(response.variables)
yield from action.async_run(response.variables)

# pylint: disable=unsubscriptable-object
if speech is not None:
Expand Down Expand Up @@ -218,8 +221,8 @@ def add_card(self, card_type, title, content):
self.card = card
return

card["title"] = title.render(self.variables)
card["content"] = content.render(self.variables)
card["title"] = title.async_render(self.variables)
card["content"] = content.async_render(self.variables)
self.card = card

def add_speech(self, speech_type, text):
Expand All @@ -229,7 +232,7 @@ def add_speech(self, speech_type, text):
key = 'ssml' if speech_type == SpeechType.ssml else 'text'

if isinstance(text, template.Template):
text = text.render(self.variables)
text = text.async_render(self.variables)

self.speech = {
'type': speech_type.value,
Expand All @@ -244,7 +247,7 @@ def add_reprompt(self, speech_type, text):

self.reprompt = {
'type': speech_type.value,
key: text.render(self.variables)
key: text.async_render(self.variables)
}

def as_dict(self):
Expand Down Expand Up @@ -284,6 +287,7 @@ def __init__(self, hass, flash_briefings):
template.attach(hass, self.flash_briefings)

# pylint: disable=too-many-branches
@callback
def get(self, request, briefing_id):
"""Handle Alexa Flash Briefing request."""
_LOGGER.debug('Received Alexa flash briefing request for: %s',
Expand All @@ -292,21 +296,21 @@ def get(self, request, briefing_id):
if self.flash_briefings.get(briefing_id) is None:
err = 'No configured Alexa flash briefing was found for: %s'
_LOGGER.error(err, briefing_id)
return self.Response(status=404)
return b'', 404

briefing = []

for item in self.flash_briefings.get(briefing_id, []):
output = {}
if item.get(CONF_TITLE) is not None:
if isinstance(item.get(CONF_TITLE), template.Template):
output[ATTR_TITLE_TEXT] = item[CONF_TITLE].render()
output[ATTR_TITLE_TEXT] = item[CONF_TITLE].async_render()
else:
output[ATTR_TITLE_TEXT] = item.get(CONF_TITLE)

if item.get(CONF_TEXT) is not None:
if isinstance(item.get(CONF_TEXT), template.Template):
output[ATTR_MAIN_TEXT] = item[CONF_TEXT].render()
output[ATTR_MAIN_TEXT] = item[CONF_TEXT].async_render()
else:
output[ATTR_MAIN_TEXT] = item.get(CONF_TEXT)

Expand All @@ -315,15 +319,15 @@ def get(self, request, briefing_id):

if item.get(CONF_AUDIO) is not None:
if isinstance(item.get(CONF_AUDIO), template.Template):
output[ATTR_STREAM_URL] = item[CONF_AUDIO].render()
output[ATTR_STREAM_URL] = item[CONF_AUDIO].async_render()
else:
output[ATTR_STREAM_URL] = item.get(CONF_AUDIO)

if item.get(CONF_DISPLAY_URL) is not None:
if isinstance(item.get(CONF_DISPLAY_URL),
template.Template):
output[ATTR_REDIRECTION_URL] = \
item[CONF_DISPLAY_URL].render()
item[CONF_DISPLAY_URL].async_render()
else:
output[ATTR_REDIRECTION_URL] = item.get(CONF_DISPLAY_URL)

Expand Down
18 changes: 9 additions & 9 deletions homeassistant/components/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ class APIStatusView(HomeAssistantView):
url = URL_API
name = "api:status"

@asyncio.coroutine
@ha.callback
def get(self, request):
"""Retrieve if API is running."""
return self.json_message('API running.')
Expand Down Expand Up @@ -141,7 +141,7 @@ class APIConfigView(HomeAssistantView):
url = URL_API_CONFIG
name = "api:config"

@asyncio.coroutine
@ha.callback
def get(self, request):
"""Get current configuration."""
return self.json(self.hass.config.as_dict())
Expand All @@ -154,7 +154,7 @@ class APIDiscoveryView(HomeAssistantView):
url = URL_API_DISCOVERY_INFO
name = "api:discovery"

@asyncio.coroutine
@ha.callback
def get(self, request):
"""Get discovery info."""
needs_auth = self.hass.config.api.api_password is not None
Expand All @@ -172,7 +172,7 @@ class APIStatesView(HomeAssistantView):
url = URL_API_STATES
name = "api:states"

@asyncio.coroutine
@ha.callback
def get(self, request):
"""Get current states."""
return self.json(self.hass.states.async_all())
Expand All @@ -184,7 +184,7 @@ class APIEntityStateView(HomeAssistantView):
url = "/api/states/{entity_id}" # TODO validation <entity(exist=False):entity_id>
name = "api:entity-state"

@asyncio.coroutine
@ha.callback
def get(self, request, entity_id):
"""Retrieve state of entity."""
state = self.hass.states.get(entity_id)
Expand Down Expand Up @@ -224,7 +224,7 @@ def post(self, request, entity_id):

return resp

@asyncio.coroutine
@ha.callback
def delete(self, request, entity_id):
"""Remove entity."""
if self.hass.states.async_remove(entity_id):
Expand All @@ -239,7 +239,7 @@ class APIEventListenersView(HomeAssistantView):
url = URL_API_EVENTS
name = "api:event-listeners"

@asyncio.coroutine
@ha.callback
def get(self, request):
"""Get event listeners."""
return self.json(async_events_json(self.hass))
Expand Down Expand Up @@ -281,7 +281,7 @@ class APIServicesView(HomeAssistantView):
url = URL_API_SERVICES
name = "api:services"

@asyncio.coroutine
@ha.callback
def get(self, request):
"""Get registered services."""
return self.json(async_services_json(self.hass))
Expand Down Expand Up @@ -384,7 +384,7 @@ class APIComponentsView(HomeAssistantView):
url = URL_API_COMPONENTS
name = "api:components"

@asyncio.coroutine
@ha.callback
def get(self, request):
"""Get current loaded components."""
return self.json(self.hass.config.components)
Expand Down
24 changes: 19 additions & 5 deletions homeassistant/components/device_tracker/locative.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/device_tracker.locative/
"""
import asyncio
from functools import partial
import logging

from homeassistant.const import HTTP_UNPROCESSABLE_ENTITY, STATE_NOT_HOME
Expand Down Expand Up @@ -35,15 +37,23 @@ def __init__(self, hass, see):
super().__init__(hass)
self.see = see

@asyncio.coroutine
def get(self, request):
"""Locative message received as GET."""
return self.post(request)
res = yield from self._handle(request.GET)
return res

@asyncio.coroutine
def post(self, request):
"""Locative message received."""
# pylint: disable=too-many-return-statements
data = request.values
data = yield from request.post()
res = yield from self._handle(data)
return res

@asyncio.coroutine
def _handle(self, data):
"""Handle locative request."""
# pylint: disable=too-many-return-statements
if 'latitude' not in data or 'longitude' not in data:
return ('Latitude and longitude not specified.',
HTTP_UNPROCESSABLE_ENTITY)
Expand All @@ -68,15 +78,19 @@ def post(self, request):
direction = data['trigger']

if direction == 'enter':
self.see(dev_id=device, location_name=location_name)
yield from self.hass.loop.run_in_executor(
None, partial(self.see, dev_id=device,
location_name=location_name))
return 'Setting location to {}'.format(location_name)

elif direction == 'exit':
current_state = self.hass.states.get(
'{}.{}'.format(DOMAIN, device))

if current_state is None or current_state.state == location_name:
self.see(dev_id=device, location_name=STATE_NOT_HOME)
yield from self.hass.loop.run_in_executor(
None, partial(self.see, dev_id=device,
location_name=STATE_NOT_HOME))
return 'Setting location to not home'
else:
# Ignore the message if it is telling us to exit a zone that we
Expand Down
28 changes: 17 additions & 11 deletions homeassistant/components/foursquare.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,15 @@
For more details about this component, please refer to the documentation at
https://home-assistant.io/components/foursquare/
"""
import asyncio
import logging
import os
import json

import requests
import voluptuous as vol

from homeassistant.const import CONF_ACCESS_TOKEN
from homeassistant.const import CONF_ACCESS_TOKEN, HTTP_BAD_REQUEST
from homeassistant.config import load_yaml_config_file
import homeassistant.helpers.config_validation as cv
from homeassistant.components.http import HomeAssistantView
Expand Down Expand Up @@ -93,16 +94,21 @@ def __init__(self, hass, push_secret):
super().__init__(hass)
self.push_secret = push_secret

@asyncio.coroutine
def post(self, request):
"""Accept the POST from Foursquare."""
raw_data = request.form
_LOGGER.debug("Received Foursquare push: %s", raw_data)
if self.push_secret != raw_data["secret"]:
try:
data = yield from request.json()
except json.decoder.JSONDecodeError:
return self.json_message('Invalid JSON', HTTP_BAD_REQUEST)

secret = data.pop('secret', None)

_LOGGER.debug("Received Foursquare push: %s", data)

if self.push_secret != secret:
_LOGGER.error("Received Foursquare push with invalid"
"push secret! Data: %s", raw_data)
return
parsed_payload = {
key: json.loads(val) for key, val in raw_data.items()
if key != "secret"
}
self.hass.bus.fire(EVENT_PUSH, parsed_payload)
"push secret: %s", secret)
return self.json_message('Incorrect secret', HTTP_BAD_REQUEST)

self.hass.bus.async_fire(EVENT_PUSH, data)
18 changes: 12 additions & 6 deletions homeassistant/components/frontend/__init__.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
"""Handle the frontend for Home Assistant."""
import asyncio
import hashlib
import json
import logging
import os

from aiohttp import web

from homeassistant.const import EVENT_HOMEASSISTANT_START
from homeassistant.components import api
from homeassistant.components.http import HomeAssistantView
Expand Down Expand Up @@ -161,13 +165,14 @@ class BootstrapView(HomeAssistantView):
url = "/api/bootstrap"
name = "api:bootstrap"

@asyncio.coroutine
def get(self, request):
"""Return all data needed to bootstrap Home Assistant."""
return self.json({
'config': self.hass.config.as_dict(),
'states': self.hass.states.all(),
'events': api.events_json(self.hass),
'services': api.services_json(self.hass),
'states': self.hass.states.async_all(),
'events': api.async_events_json(self.hass),
'services': api.async_services_json(self.hass),
'panels': PANELS,
})

Expand All @@ -193,6 +198,7 @@ def __init__(self, hass, extra_urls):
)
)

@asyncio.coroutine
def get(self, request, entity_id=None):
"""Serve the index view."""
if self.hass.wsgi.development:
Expand Down Expand Up @@ -230,7 +236,7 @@ def get(self, request, entity_id=None):
icons_url=icons_url, icons=FINGERPRINTS['mdi.html'],
panel_url=panel_url, panels=PANELS)

return self.Response(resp, mimetype='text/html')
return web.Response(text=resp, content_type='text/html')


class ManifestJSONView(HomeAssistantView):
Expand All @@ -240,8 +246,8 @@ class ManifestJSONView(HomeAssistantView):
url = "/manifest.json"
name = "manifestjson"

@asyncio.coroutine
def get(self, request):
"""Return the manifest.json."""
import json
msg = json.dumps(MANIFEST_JSON, sort_keys=True).encode('UTF-8')
return self.Response(msg, mimetype="application/manifest+json")
return web.Response(body=msg, content_type="application/manifest+json")
Loading

0 comments on commit 4615816

Please sign in to comment.