mirror of
https://github.com/home-assistant/core.git
synced 2025-07-19 19:27:45 +00:00
Use constants (#14647)
This commit is contained in:
parent
36e8157268
commit
2f4c5f949b
@ -2,7 +2,7 @@
|
|||||||
Rest API for Home Assistant.
|
Rest API for Home Assistant.
|
||||||
|
|
||||||
For more details about the RESTful API, please refer to the documentation at
|
For more details about the RESTful API, please refer to the documentation at
|
||||||
https://home-assistant.io/developers/api/
|
https://developers.home-assistant.io/docs/en/external_api_rest.html
|
||||||
"""
|
"""
|
||||||
import asyncio
|
import asyncio
|
||||||
import json
|
import json
|
||||||
@ -11,31 +11,34 @@ import logging
|
|||||||
from aiohttp import web
|
from aiohttp import web
|
||||||
import async_timeout
|
import async_timeout
|
||||||
|
|
||||||
import homeassistant.core as ha
|
|
||||||
import homeassistant.remote as rem
|
|
||||||
from homeassistant.bootstrap import DATA_LOGGING
|
from homeassistant.bootstrap import DATA_LOGGING
|
||||||
from homeassistant.const import (
|
|
||||||
EVENT_HOMEASSISTANT_STOP, EVENT_TIME_CHANGED,
|
|
||||||
HTTP_BAD_REQUEST, HTTP_CREATED, HTTP_NOT_FOUND,
|
|
||||||
MATCH_ALL, URL_API, URL_API_COMPONENTS,
|
|
||||||
URL_API_CONFIG, URL_API_DISCOVERY_INFO, URL_API_ERROR_LOG,
|
|
||||||
URL_API_EVENTS, URL_API_SERVICES,
|
|
||||||
URL_API_STATES, URL_API_STATES_ENTITY, URL_API_STREAM, URL_API_TEMPLATE,
|
|
||||||
__version__)
|
|
||||||
from homeassistant.exceptions import TemplateError
|
|
||||||
from homeassistant.helpers.state import AsyncTrackStates
|
|
||||||
from homeassistant.helpers.service import async_get_all_descriptions
|
|
||||||
from homeassistant.helpers import template
|
|
||||||
from homeassistant.components.http import HomeAssistantView
|
from homeassistant.components.http import HomeAssistantView
|
||||||
|
from homeassistant.const import (
|
||||||
|
EVENT_HOMEASSISTANT_STOP, EVENT_TIME_CHANGED, HTTP_BAD_REQUEST,
|
||||||
|
HTTP_CREATED, HTTP_NOT_FOUND, MATCH_ALL, URL_API, URL_API_COMPONENTS,
|
||||||
|
URL_API_CONFIG, URL_API_DISCOVERY_INFO, URL_API_ERROR_LOG, URL_API_EVENTS,
|
||||||
|
URL_API_SERVICES, URL_API_STATES, URL_API_STATES_ENTITY, URL_API_STREAM,
|
||||||
|
URL_API_TEMPLATE, __version__)
|
||||||
|
import homeassistant.core as ha
|
||||||
|
from homeassistant.exceptions import TemplateError
|
||||||
|
from homeassistant.helpers import template
|
||||||
|
from homeassistant.helpers.service import async_get_all_descriptions
|
||||||
|
from homeassistant.helpers.state import AsyncTrackStates
|
||||||
|
import homeassistant.remote as rem
|
||||||
|
|
||||||
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
ATTR_BASE_URL = 'base_url'
|
||||||
|
ATTR_LOCATION_NAME = 'location_name'
|
||||||
|
ATTR_REQUIRES_API_PASSWORD = 'requires_api_password'
|
||||||
|
ATTR_VERSION = 'version'
|
||||||
|
|
||||||
DOMAIN = 'api'
|
DOMAIN = 'api'
|
||||||
DEPENDENCIES = ['http']
|
DEPENDENCIES = ['http']
|
||||||
|
|
||||||
STREAM_PING_PAYLOAD = "ping"
|
STREAM_PING_PAYLOAD = 'ping'
|
||||||
STREAM_PING_INTERVAL = 50 # seconds
|
STREAM_PING_INTERVAL = 50 # seconds
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
|
|
||||||
def setup(hass, config):
|
def setup(hass, config):
|
||||||
"""Register the API with the HTTP interface."""
|
"""Register the API with the HTTP interface."""
|
||||||
@ -62,19 +65,19 @@ class APIStatusView(HomeAssistantView):
|
|||||||
"""View to handle Status requests."""
|
"""View to handle Status requests."""
|
||||||
|
|
||||||
url = URL_API
|
url = URL_API
|
||||||
name = "api:status"
|
name = 'api:status'
|
||||||
|
|
||||||
@ha.callback
|
@ha.callback
|
||||||
def get(self, request):
|
def get(self, request):
|
||||||
"""Retrieve if API is running."""
|
"""Retrieve if API is running."""
|
||||||
return self.json_message('API running.')
|
return self.json_message("API running.")
|
||||||
|
|
||||||
|
|
||||||
class APIEventStream(HomeAssistantView):
|
class APIEventStream(HomeAssistantView):
|
||||||
"""View to handle EventStream requests."""
|
"""View to handle EventStream requests."""
|
||||||
|
|
||||||
url = URL_API_STREAM
|
url = URL_API_STREAM
|
||||||
name = "api:stream"
|
name = 'api:stream'
|
||||||
|
|
||||||
async def get(self, request):
|
async def get(self, request):
|
||||||
"""Provide a streaming interface for the event bus."""
|
"""Provide a streaming interface for the event bus."""
|
||||||
@ -95,7 +98,7 @@ class APIEventStream(HomeAssistantView):
|
|||||||
if restrict and event.event_type not in restrict:
|
if restrict and event.event_type not in restrict:
|
||||||
return
|
return
|
||||||
|
|
||||||
_LOGGER.debug('STREAM %s FORWARDING %s', id(stop_obj), event)
|
_LOGGER.debug("STREAM %s FORWARDING %s", id(stop_obj), event)
|
||||||
|
|
||||||
if event.event_type == EVENT_HOMEASSISTANT_STOP:
|
if event.event_type == EVENT_HOMEASSISTANT_STOP:
|
||||||
data = stop_obj
|
data = stop_obj
|
||||||
@ -111,7 +114,7 @@ class APIEventStream(HomeAssistantView):
|
|||||||
unsub_stream = hass.bus.async_listen(MATCH_ALL, forward_events)
|
unsub_stream = hass.bus.async_listen(MATCH_ALL, forward_events)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
_LOGGER.debug('STREAM %s ATTACHED', id(stop_obj))
|
_LOGGER.debug("STREAM %s ATTACHED", id(stop_obj))
|
||||||
|
|
||||||
# Fire off one message so browsers fire open event right away
|
# Fire off one message so browsers fire open event right away
|
||||||
await to_write.put(STREAM_PING_PAYLOAD)
|
await to_write.put(STREAM_PING_PAYLOAD)
|
||||||
@ -126,25 +129,25 @@ class APIEventStream(HomeAssistantView):
|
|||||||
break
|
break
|
||||||
|
|
||||||
msg = "data: {}\n\n".format(payload)
|
msg = "data: {}\n\n".format(payload)
|
||||||
_LOGGER.debug('STREAM %s WRITING %s', id(stop_obj),
|
_LOGGER.debug(
|
||||||
msg.strip())
|
"STREAM %s WRITING %s", id(stop_obj), msg.strip())
|
||||||
await response.write(msg.encode("UTF-8"))
|
await response.write(msg.encode('UTF-8'))
|
||||||
except asyncio.TimeoutError:
|
except asyncio.TimeoutError:
|
||||||
await to_write.put(STREAM_PING_PAYLOAD)
|
await to_write.put(STREAM_PING_PAYLOAD)
|
||||||
|
|
||||||
except asyncio.CancelledError:
|
except asyncio.CancelledError:
|
||||||
_LOGGER.debug('STREAM %s ABORT', id(stop_obj))
|
_LOGGER.debug("STREAM %s ABORT", id(stop_obj))
|
||||||
|
|
||||||
finally:
|
finally:
|
||||||
_LOGGER.debug('STREAM %s RESPONSE CLOSED', id(stop_obj))
|
_LOGGER.debug("STREAM %s RESPONSE CLOSED", id(stop_obj))
|
||||||
unsub_stream()
|
unsub_stream()
|
||||||
|
|
||||||
|
|
||||||
class APIConfigView(HomeAssistantView):
|
class APIConfigView(HomeAssistantView):
|
||||||
"""View to handle Config requests."""
|
"""View to handle Configuration requests."""
|
||||||
|
|
||||||
url = URL_API_CONFIG
|
url = URL_API_CONFIG
|
||||||
name = "api:config"
|
name = 'api:config'
|
||||||
|
|
||||||
@ha.callback
|
@ha.callback
|
||||||
def get(self, request):
|
def get(self, request):
|
||||||
@ -153,22 +156,22 @@ class APIConfigView(HomeAssistantView):
|
|||||||
|
|
||||||
|
|
||||||
class APIDiscoveryView(HomeAssistantView):
|
class APIDiscoveryView(HomeAssistantView):
|
||||||
"""View to provide discovery info."""
|
"""View to provide Discovery information."""
|
||||||
|
|
||||||
requires_auth = False
|
requires_auth = False
|
||||||
url = URL_API_DISCOVERY_INFO
|
url = URL_API_DISCOVERY_INFO
|
||||||
name = "api:discovery"
|
name = 'api:discovery'
|
||||||
|
|
||||||
@ha.callback
|
@ha.callback
|
||||||
def get(self, request):
|
def get(self, request):
|
||||||
"""Get discovery info."""
|
"""Get discovery information."""
|
||||||
hass = request.app['hass']
|
hass = request.app['hass']
|
||||||
needs_auth = hass.config.api.api_password is not None
|
needs_auth = hass.config.api.api_password is not None
|
||||||
return self.json({
|
return self.json({
|
||||||
'base_url': hass.config.api.base_url,
|
ATTR_BASE_URL: hass.config.api.base_url,
|
||||||
'location_name': hass.config.location_name,
|
ATTR_LOCATION_NAME: hass.config.location_name,
|
||||||
'requires_api_password': needs_auth,
|
ATTR_REQUIRES_API_PASSWORD: needs_auth,
|
||||||
'version': __version__
|
ATTR_VERSION: __version__,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
@ -187,8 +190,8 @@ class APIStatesView(HomeAssistantView):
|
|||||||
class APIEntityStateView(HomeAssistantView):
|
class APIEntityStateView(HomeAssistantView):
|
||||||
"""View to handle EntityState requests."""
|
"""View to handle EntityState requests."""
|
||||||
|
|
||||||
url = "/api/states/{entity_id}"
|
url = '/api/states/{entity_id}'
|
||||||
name = "api:entity-state"
|
name = 'api:entity-state'
|
||||||
|
|
||||||
@ha.callback
|
@ha.callback
|
||||||
def get(self, request, entity_id):
|
def get(self, request, entity_id):
|
||||||
@ -196,7 +199,7 @@ class APIEntityStateView(HomeAssistantView):
|
|||||||
state = request.app['hass'].states.get(entity_id)
|
state = request.app['hass'].states.get(entity_id)
|
||||||
if state:
|
if state:
|
||||||
return self.json(state)
|
return self.json(state)
|
||||||
return self.json_message('Entity not found', HTTP_NOT_FOUND)
|
return self.json_message("Entity not found.", HTTP_NOT_FOUND)
|
||||||
|
|
||||||
async def post(self, request, entity_id):
|
async def post(self, request, entity_id):
|
||||||
"""Update state of entity."""
|
"""Update state of entity."""
|
||||||
@ -204,13 +207,13 @@ class APIEntityStateView(HomeAssistantView):
|
|||||||
try:
|
try:
|
||||||
data = await request.json()
|
data = await request.json()
|
||||||
except ValueError:
|
except ValueError:
|
||||||
return self.json_message('Invalid JSON specified',
|
return self.json_message(
|
||||||
HTTP_BAD_REQUEST)
|
"Invalid JSON specified.", HTTP_BAD_REQUEST)
|
||||||
|
|
||||||
new_state = data.get('state')
|
new_state = data.get('state')
|
||||||
|
|
||||||
if new_state is None:
|
if new_state is None:
|
||||||
return self.json_message('No state specified', HTTP_BAD_REQUEST)
|
return self.json_message("No state specified.", HTTP_BAD_REQUEST)
|
||||||
|
|
||||||
attributes = data.get('attributes')
|
attributes = data.get('attributes')
|
||||||
force_update = data.get('force_update', False)
|
force_update = data.get('force_update', False)
|
||||||
@ -232,15 +235,15 @@ class APIEntityStateView(HomeAssistantView):
|
|||||||
def delete(self, request, entity_id):
|
def delete(self, request, entity_id):
|
||||||
"""Remove entity."""
|
"""Remove entity."""
|
||||||
if request.app['hass'].states.async_remove(entity_id):
|
if request.app['hass'].states.async_remove(entity_id):
|
||||||
return self.json_message('Entity removed')
|
return self.json_message("Entity removed.")
|
||||||
return self.json_message('Entity not found', HTTP_NOT_FOUND)
|
return self.json_message("Entity not found.", HTTP_NOT_FOUND)
|
||||||
|
|
||||||
|
|
||||||
class APIEventListenersView(HomeAssistantView):
|
class APIEventListenersView(HomeAssistantView):
|
||||||
"""View to handle EventListeners requests."""
|
"""View to handle EventListeners requests."""
|
||||||
|
|
||||||
url = URL_API_EVENTS
|
url = URL_API_EVENTS
|
||||||
name = "api:event-listeners"
|
name = 'api:event-listeners'
|
||||||
|
|
||||||
@ha.callback
|
@ha.callback
|
||||||
def get(self, request):
|
def get(self, request):
|
||||||
@ -252,7 +255,7 @@ class APIEventView(HomeAssistantView):
|
|||||||
"""View to handle Event requests."""
|
"""View to handle Event requests."""
|
||||||
|
|
||||||
url = '/api/events/{event_type}'
|
url = '/api/events/{event_type}'
|
||||||
name = "api:event"
|
name = 'api:event'
|
||||||
|
|
||||||
async def post(self, request, event_type):
|
async def post(self, request, event_type):
|
||||||
"""Fire events."""
|
"""Fire events."""
|
||||||
@ -260,12 +263,12 @@ class APIEventView(HomeAssistantView):
|
|||||||
try:
|
try:
|
||||||
event_data = json.loads(body) if body else None
|
event_data = json.loads(body) if body else None
|
||||||
except ValueError:
|
except ValueError:
|
||||||
return self.json_message('Event data should be valid JSON',
|
return self.json_message(
|
||||||
HTTP_BAD_REQUEST)
|
"Event data should be valid JSON.", HTTP_BAD_REQUEST)
|
||||||
|
|
||||||
if event_data is not None and not isinstance(event_data, dict):
|
if event_data is not None and not isinstance(event_data, dict):
|
||||||
return self.json_message('Event data should be a JSON object',
|
return self.json_message(
|
||||||
HTTP_BAD_REQUEST)
|
"Event data should be a JSON object", HTTP_BAD_REQUEST)
|
||||||
|
|
||||||
# Special case handling for event STATE_CHANGED
|
# Special case handling for event STATE_CHANGED
|
||||||
# We will try to convert state dicts back to State objects
|
# We will try to convert state dicts back to State objects
|
||||||
@ -276,8 +279,8 @@ class APIEventView(HomeAssistantView):
|
|||||||
if state:
|
if state:
|
||||||
event_data[key] = state
|
event_data[key] = state
|
||||||
|
|
||||||
request.app['hass'].bus.async_fire(event_type, event_data,
|
request.app['hass'].bus.async_fire(
|
||||||
ha.EventOrigin.remote)
|
event_type, event_data, ha.EventOrigin.remote)
|
||||||
|
|
||||||
return self.json_message("Event {} fired.".format(event_type))
|
return self.json_message("Event {} fired.".format(event_type))
|
||||||
|
|
||||||
@ -286,7 +289,7 @@ class APIServicesView(HomeAssistantView):
|
|||||||
"""View to handle Services requests."""
|
"""View to handle Services requests."""
|
||||||
|
|
||||||
url = URL_API_SERVICES
|
url = URL_API_SERVICES
|
||||||
name = "api:services"
|
name = 'api:services'
|
||||||
|
|
||||||
async def get(self, request):
|
async def get(self, request):
|
||||||
"""Get registered services."""
|
"""Get registered services."""
|
||||||
@ -297,8 +300,8 @@ class APIServicesView(HomeAssistantView):
|
|||||||
class APIDomainServicesView(HomeAssistantView):
|
class APIDomainServicesView(HomeAssistantView):
|
||||||
"""View to handle DomainServices requests."""
|
"""View to handle DomainServices requests."""
|
||||||
|
|
||||||
url = "/api/services/{domain}/{service}"
|
url = '/api/services/{domain}/{service}'
|
||||||
name = "api:domain-services"
|
name = 'api:domain-services'
|
||||||
|
|
||||||
async def post(self, request, domain, service):
|
async def post(self, request, domain, service):
|
||||||
"""Call a service.
|
"""Call a service.
|
||||||
@ -310,8 +313,8 @@ class APIDomainServicesView(HomeAssistantView):
|
|||||||
try:
|
try:
|
||||||
data = json.loads(body) if body else None
|
data = json.loads(body) if body else None
|
||||||
except ValueError:
|
except ValueError:
|
||||||
return self.json_message('Data should be valid JSON',
|
return self.json_message(
|
||||||
HTTP_BAD_REQUEST)
|
"Data should be valid JSON.", HTTP_BAD_REQUEST)
|
||||||
|
|
||||||
with AsyncTrackStates(hass) as changed_states:
|
with AsyncTrackStates(hass) as changed_states:
|
||||||
await hass.services.async_call(domain, service, data, True)
|
await hass.services.async_call(domain, service, data, True)
|
||||||
@ -323,7 +326,7 @@ class APIComponentsView(HomeAssistantView):
|
|||||||
"""View to handle Components requests."""
|
"""View to handle Components requests."""
|
||||||
|
|
||||||
url = URL_API_COMPONENTS
|
url = URL_API_COMPONENTS
|
||||||
name = "api:components"
|
name = 'api:components'
|
||||||
|
|
||||||
@ha.callback
|
@ha.callback
|
||||||
def get(self, request):
|
def get(self, request):
|
||||||
@ -332,10 +335,10 @@ class APIComponentsView(HomeAssistantView):
|
|||||||
|
|
||||||
|
|
||||||
class APITemplateView(HomeAssistantView):
|
class APITemplateView(HomeAssistantView):
|
||||||
"""View to handle requests."""
|
"""View to handle Template requests."""
|
||||||
|
|
||||||
url = URL_API_TEMPLATE
|
url = URL_API_TEMPLATE
|
||||||
name = "api:template"
|
name = 'api:template'
|
||||||
|
|
||||||
async def post(self, request):
|
async def post(self, request):
|
||||||
"""Render a template."""
|
"""Render a template."""
|
||||||
@ -344,30 +347,29 @@ class APITemplateView(HomeAssistantView):
|
|||||||
tpl = template.Template(data['template'], request.app['hass'])
|
tpl = template.Template(data['template'], request.app['hass'])
|
||||||
return tpl.async_render(data.get('variables'))
|
return tpl.async_render(data.get('variables'))
|
||||||
except (ValueError, TemplateError) as ex:
|
except (ValueError, TemplateError) as ex:
|
||||||
return self.json_message('Error rendering template: {}'.format(ex),
|
return self.json_message(
|
||||||
HTTP_BAD_REQUEST)
|
"Error rendering template: {}".format(ex), HTTP_BAD_REQUEST)
|
||||||
|
|
||||||
|
|
||||||
class APIErrorLog(HomeAssistantView):
|
class APIErrorLog(HomeAssistantView):
|
||||||
"""View to fetch the error log."""
|
"""View to fetch the API error log."""
|
||||||
|
|
||||||
url = URL_API_ERROR_LOG
|
url = URL_API_ERROR_LOG
|
||||||
name = "api:error_log"
|
name = 'api:error_log'
|
||||||
|
|
||||||
async def get(self, request):
|
async def get(self, request):
|
||||||
"""Retrieve API error log."""
|
"""Retrieve API error log."""
|
||||||
return web.FileResponse(
|
return web.FileResponse(request.app['hass'].data[DATA_LOGGING])
|
||||||
request.app['hass'].data[DATA_LOGGING])
|
|
||||||
|
|
||||||
|
|
||||||
async def async_services_json(hass):
|
async def async_services_json(hass):
|
||||||
"""Generate services data to JSONify."""
|
"""Generate services data to JSONify."""
|
||||||
descriptions = await async_get_all_descriptions(hass)
|
descriptions = await async_get_all_descriptions(hass)
|
||||||
return [{"domain": key, "services": value}
|
return [{'domain': key, 'services': value}
|
||||||
for key, value in descriptions.items()]
|
for key, value in descriptions.items()]
|
||||||
|
|
||||||
|
|
||||||
def async_events_json(hass):
|
def async_events_json(hass):
|
||||||
"""Generate event data to JSONify."""
|
"""Generate event data to JSONify."""
|
||||||
return [{"event": key, "listener_count": value}
|
return [{'event': key, 'listener_count': value}
|
||||||
for key, value in hass.bus.async_listeners().items()]
|
for key, value in hass.bus.async_listeners().items()]
|
||||||
|
Loading…
x
Reference in New Issue
Block a user