mirror of
https://github.com/home-assistant/core.git
synced 2026-01-06 23:57:17 +01:00
Compare commits
19 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
937eba3dbe | ||
|
|
9d8054e6e2 | ||
|
|
d4cd39e43e | ||
|
|
1bf49ce5a3 | ||
|
|
7cf1f4f9fe | ||
|
|
268d129ea9 | ||
|
|
b8f246356a | ||
|
|
e6ffc790f2 | ||
|
|
b85189e699 | ||
|
|
f202114ead | ||
|
|
fff6927f9c | ||
|
|
ad0ec66353 | ||
|
|
592edd10ef | ||
|
|
d75d75e49f | ||
|
|
1c9b750e36 | ||
|
|
33a7075883 | ||
|
|
cc00f3cd2e | ||
|
|
22624715a9 | ||
|
|
c37dcacf54 |
@@ -5,7 +5,7 @@ import os
|
||||
import sys
|
||||
from time import time
|
||||
from collections import OrderedDict
|
||||
from typing import Any, Optional, Dict
|
||||
from typing import Any, Optional, Dict, Set
|
||||
|
||||
import voluptuous as vol
|
||||
|
||||
@@ -127,10 +127,7 @@ async def async_from_config_dict(config: Dict[str, Any],
|
||||
hass.config_entries = config_entries.ConfigEntries(hass, config)
|
||||
await hass.config_entries.async_initialize()
|
||||
|
||||
# Filter out the repeating and common config section [homeassistant]
|
||||
components = set(key.split(' ')[0] for key in config.keys()
|
||||
if key != core.DOMAIN)
|
||||
components.update(hass.config_entries.async_domains())
|
||||
components = _get_components(hass, config)
|
||||
|
||||
# Resolve all dependencies of all components.
|
||||
for component in list(components):
|
||||
@@ -391,3 +388,21 @@ async def async_mount_local_lib_path(config_dir: str) -> str:
|
||||
if lib_dir not in sys.path:
|
||||
sys.path.insert(0, lib_dir)
|
||||
return deps_dir
|
||||
|
||||
|
||||
@core.callback
|
||||
def _get_components(hass: core.HomeAssistant,
|
||||
config: Dict[str, Any]) -> Set[str]:
|
||||
"""Get components to set up."""
|
||||
# Filter out the repeating and common config section [homeassistant]
|
||||
components = set(key.split(' ')[0] for key in config.keys()
|
||||
if key != core.DOMAIN)
|
||||
|
||||
# Add config entry domains
|
||||
components.update(hass.config_entries.async_domains()) # type: ignore
|
||||
|
||||
# Make sure the Hass.io component is loaded
|
||||
if 'HASSIO' in os.environ:
|
||||
components.add('hassio')
|
||||
|
||||
return components
|
||||
|
||||
@@ -18,7 +18,7 @@ from homeassistant.const import (
|
||||
STATE_ALARM_ARMED_CUSTOM_BYPASS)
|
||||
|
||||
|
||||
REQUIREMENTS = ['total_connect_client==0.22']
|
||||
REQUIREMENTS = ['total_connect_client==0.24']
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ from .const import (
|
||||
CONF_USER_POOL_ID, DOMAIN, MODE_DEV, MODE_PROD)
|
||||
from .prefs import CloudPreferences
|
||||
|
||||
REQUIREMENTS = ['hass-nabucasa==0.7']
|
||||
REQUIREMENTS = ['hass-nabucasa==0.8']
|
||||
DEPENDENCIES = ['http']
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
@@ -9,7 +9,6 @@ loaded before the EVENT_PLATFORM_DISCOVERED is fired.
|
||||
import json
|
||||
from datetime import timedelta
|
||||
import logging
|
||||
import os
|
||||
|
||||
import voluptuous as vol
|
||||
|
||||
@@ -199,10 +198,6 @@ async def async_setup(hass, config):
|
||||
"""Schedule the first discovery when Home Assistant starts up."""
|
||||
async_track_point_in_utc_time(hass, scan_devices, dt_util.utcnow())
|
||||
|
||||
# Discovery for local services
|
||||
if 'HASSIO' in os.environ:
|
||||
hass.async_create_task(new_service_found(SERVICE_HASSIO, {}))
|
||||
|
||||
hass.bus.async_listen_once(EVENT_HOMEASSISTANT_START, schedule_first)
|
||||
|
||||
return True
|
||||
|
||||
@@ -21,7 +21,7 @@ from homeassistant.loader import bind_hass
|
||||
|
||||
from .storage import async_setup_frontend_storage
|
||||
|
||||
REQUIREMENTS = ['home-assistant-frontend==20190316.0']
|
||||
REQUIREMENTS = ['home-assistant-frontend==20190320.0']
|
||||
|
||||
DOMAIN = 'frontend'
|
||||
DEPENDENCIES = ['api', 'websocket_api', 'http', 'system_log',
|
||||
|
||||
@@ -7,6 +7,7 @@ import voluptuous as vol
|
||||
|
||||
from homeassistant.auth.const import GROUP_ID_ADMIN
|
||||
from homeassistant.components import SERVICE_CHECK_CONFIG
|
||||
import homeassistant.config as conf_util
|
||||
from homeassistant.const import (
|
||||
ATTR_NAME, SERVICE_HOMEASSISTANT_RESTART, SERVICE_HOMEASSISTANT_STOP)
|
||||
from homeassistant.core import DOMAIN as HASS_DOMAIN, callback
|
||||
@@ -130,23 +131,6 @@ def is_hassio(hass):
|
||||
return DOMAIN in hass.config.components
|
||||
|
||||
|
||||
@bind_hass
|
||||
async def async_check_config(hass):
|
||||
"""Check configuration over Hass.io API."""
|
||||
hassio = hass.data[DOMAIN]
|
||||
|
||||
try:
|
||||
result = await hassio.check_homeassistant_config()
|
||||
except HassioAPIError as err:
|
||||
_LOGGER.error("Error on Hass.io API: %s", err)
|
||||
raise HomeAssistantError() from None
|
||||
else:
|
||||
if result['result'] == "error":
|
||||
return result['message']
|
||||
|
||||
return None
|
||||
|
||||
|
||||
async def async_setup(hass, config):
|
||||
"""Set up the Hass.io component."""
|
||||
# Check local setup
|
||||
@@ -259,9 +243,13 @@ async def async_setup(hass, config):
|
||||
await hassio.stop_homeassistant()
|
||||
return
|
||||
|
||||
error = await async_check_config(hass)
|
||||
if error:
|
||||
_LOGGER.error(error)
|
||||
try:
|
||||
errors = await conf_util.async_check_ha_config_file(hass)
|
||||
except HomeAssistantError:
|
||||
return
|
||||
|
||||
if errors:
|
||||
_LOGGER.error(errors)
|
||||
hass.components.persistent_notification.async_create(
|
||||
"Config error. See dev-info panel for details.",
|
||||
"Config validating", "{0}.check_config".format(HASS_DOMAIN))
|
||||
|
||||
@@ -97,13 +97,6 @@ class HassIO:
|
||||
"""
|
||||
return self.send_command("/homeassistant/stop")
|
||||
|
||||
def check_homeassistant_config(self):
|
||||
"""Check Home-Assistant config with Hass.io API.
|
||||
|
||||
This method return a coroutine.
|
||||
"""
|
||||
return self.send_command("/homeassistant/check", timeout=600)
|
||||
|
||||
@_api_data
|
||||
def retrieve_discovery_messages(self):
|
||||
"""Return all discovery data from Hass.io API.
|
||||
|
||||
@@ -39,8 +39,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
|
||||
|
||||
def get_service(hass, config, discovery_info=None):
|
||||
"""Get the AWS Lambda notification service."""
|
||||
context_str = json.dumps({'hass': hass.config.as_dict(),
|
||||
'custom': config[CONF_CONTEXT]}, cls=JSONEncoder)
|
||||
context_str = json.dumps({'custom': config[CONF_CONTEXT]}, cls=JSONEncoder)
|
||||
context_b64 = base64.b64encode(context_str.encode('utf-8'))
|
||||
context = context_b64.decode('utf-8')
|
||||
|
||||
|
||||
@@ -120,10 +120,16 @@ class Stream:
|
||||
"""Remove provider output stream."""
|
||||
if provider.format in self._outputs:
|
||||
del self._outputs[provider.format]
|
||||
self.check_idle()
|
||||
|
||||
if not self._outputs:
|
||||
self.stop()
|
||||
|
||||
def check_idle(self):
|
||||
"""Reset access token if all providers are idle."""
|
||||
if all([p.idle for p in self._outputs.values()]):
|
||||
self.access_token = None
|
||||
|
||||
def start(self):
|
||||
"""Start a stream."""
|
||||
if self._thread is None or not self._thread.isAlive():
|
||||
|
||||
@@ -43,6 +43,7 @@ class StreamOutput:
|
||||
|
||||
def __init__(self, stream) -> None:
|
||||
"""Initialize a stream output."""
|
||||
self.idle = False
|
||||
self._stream = stream
|
||||
self._cursor = None
|
||||
self._event = asyncio.Event()
|
||||
@@ -77,10 +78,11 @@ class StreamOutput:
|
||||
|
||||
def get_segment(self, sequence: int = None) -> Any:
|
||||
"""Retrieve a specific segment, or the whole list."""
|
||||
self.idle = False
|
||||
# Reset idle timeout
|
||||
if self._unsub is not None:
|
||||
self._unsub()
|
||||
self._unsub = async_call_later(self._stream.hass, 300, self._cleanup)
|
||||
self._unsub = async_call_later(self._stream.hass, 300, self._timeout)
|
||||
|
||||
if not sequence:
|
||||
return self._segments
|
||||
@@ -109,7 +111,7 @@ class StreamOutput:
|
||||
# Start idle timeout when we start recieving data
|
||||
if self._unsub is None:
|
||||
self._unsub = async_call_later(
|
||||
self._stream.hass, 300, self._cleanup)
|
||||
self._stream.hass, 300, self._timeout)
|
||||
|
||||
if segment is None:
|
||||
self._event.set()
|
||||
@@ -124,7 +126,15 @@ class StreamOutput:
|
||||
self._event.clear()
|
||||
|
||||
@callback
|
||||
def _cleanup(self, _now=None):
|
||||
def _timeout(self, _now=None):
|
||||
"""Handle stream timeout."""
|
||||
if self._stream.keepalive:
|
||||
self.idle = True
|
||||
self._stream.check_idle()
|
||||
else:
|
||||
self._cleanup()
|
||||
|
||||
def _cleanup(self):
|
||||
"""Remove provider."""
|
||||
self._segments = []
|
||||
self._stream.remove_provider(self)
|
||||
|
||||
@@ -10,7 +10,7 @@ from homeassistant.helpers import config_validation as cv
|
||||
from homeassistant.const import CONF_USERNAME, CONF_PASSWORD
|
||||
from homeassistant.util import Throttle
|
||||
|
||||
REQUIREMENTS = ['python-tado==0.2.3']
|
||||
REQUIREMENTS = ['python-tado==0.2.8']
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@@ -52,9 +52,9 @@ class TadoDeviceScanner(DeviceScanner):
|
||||
|
||||
# If there's a home_id, we need a different API URL
|
||||
if self.home_id is None:
|
||||
self.tadoapiurl = 'https://my.tado.com/api/v2/me'
|
||||
self.tadoapiurl = 'https://auth.tado.com/api/v2/me'
|
||||
else:
|
||||
self.tadoapiurl = 'https://my.tado.com/api/v2' \
|
||||
self.tadoapiurl = 'https://auth.tado.com/api/v2' \
|
||||
'/homes/{home_id}/mobileDevices'
|
||||
|
||||
# The API URL always needs a username and password
|
||||
|
||||
@@ -16,7 +16,7 @@ from .const import (
|
||||
CONF_CLIENT_ID, CONF_CLIENT_SECRET, CONF_DISPLAY, CONF_TENANT,
|
||||
DATA_TOON_CLIENT, DATA_TOON_CONFIG, DOMAIN)
|
||||
|
||||
REQUIREMENTS = ['toonapilib==3.2.1']
|
||||
REQUIREMENTS = ['toonapilib==3.2.2']
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ DEPENDENCIES = ['toon']
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
MIN_TIME_BETWEEN_UPDATES = timedelta(seconds=5)
|
||||
SCAN_INTERVAL = timedelta(seconds=30)
|
||||
SCAN_INTERVAL = timedelta(seconds=300)
|
||||
|
||||
|
||||
async def async_setup_entry(hass: HomeAssistantType, entry: ConfigEntry,
|
||||
|
||||
@@ -22,7 +22,7 @@ _LOGGER = logging.getLogger(__name__)
|
||||
SUPPORT_FLAGS = SUPPORT_TARGET_TEMPERATURE | SUPPORT_OPERATION_MODE
|
||||
|
||||
MIN_TIME_BETWEEN_UPDATES = timedelta(seconds=5)
|
||||
SCAN_INTERVAL = timedelta(seconds=30)
|
||||
SCAN_INTERVAL = timedelta(seconds=300)
|
||||
|
||||
HA_TOON = {
|
||||
STATE_AUTO: 'Comfort',
|
||||
|
||||
@@ -16,7 +16,7 @@ DEPENDENCIES = ['toon']
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
MIN_TIME_BETWEEN_UPDATES = timedelta(seconds=5)
|
||||
SCAN_INTERVAL = timedelta(seconds=30)
|
||||
SCAN_INTERVAL = timedelta(seconds=300)
|
||||
|
||||
|
||||
async def async_setup_entry(hass: HomeAssistantType, entry: ConfigEntry,
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
"""Commands part of Websocket API."""
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.const import MATCH_ALL, EVENT_TIME_CHANGED
|
||||
from homeassistant.auth.permissions.const import POLICY_READ
|
||||
from homeassistant.const import (
|
||||
MATCH_ALL, EVENT_TIME_CHANGED, EVENT_STATE_CHANGED)
|
||||
from homeassistant.core import callback, DOMAIN as HASS_DOMAIN
|
||||
from homeassistant.exceptions import Unauthorized, ServiceNotFound, \
|
||||
HomeAssistantError
|
||||
@@ -42,20 +44,37 @@ def handle_subscribe_events(hass, connection, msg):
|
||||
|
||||
Async friendly.
|
||||
"""
|
||||
if not connection.user.is_admin:
|
||||
from .permissions import SUBSCRIBE_WHITELIST
|
||||
|
||||
event_type = msg['event_type']
|
||||
|
||||
if (event_type not in SUBSCRIBE_WHITELIST and
|
||||
not connection.user.is_admin):
|
||||
raise Unauthorized
|
||||
|
||||
async def forward_events(event):
|
||||
"""Forward events to websocket."""
|
||||
if event.event_type == EVENT_TIME_CHANGED:
|
||||
return
|
||||
if event_type == EVENT_STATE_CHANGED:
|
||||
@callback
|
||||
def forward_events(event):
|
||||
"""Forward state changed events to websocket."""
|
||||
if not connection.user.permissions.check_entity(
|
||||
event.data['entity_id'], POLICY_READ):
|
||||
return
|
||||
|
||||
connection.send_message(messages.event_message(
|
||||
msg['id'], event.as_dict()
|
||||
))
|
||||
connection.send_message(messages.event_message(msg['id'], event))
|
||||
|
||||
else:
|
||||
@callback
|
||||
def forward_events(event):
|
||||
"""Forward events to websocket."""
|
||||
if event.event_type == EVENT_TIME_CHANGED:
|
||||
return
|
||||
|
||||
connection.send_message(messages.event_message(
|
||||
msg['id'], event.as_dict()
|
||||
))
|
||||
|
||||
connection.subscriptions[msg['id']] = hass.bus.async_listen(
|
||||
msg['event_type'], forward_events)
|
||||
event_type, forward_events)
|
||||
|
||||
connection.send_message(messages.result_message(msg['id']))
|
||||
|
||||
|
||||
23
homeassistant/components/websocket_api/permissions.py
Normal file
23
homeassistant/components/websocket_api/permissions.py
Normal file
@@ -0,0 +1,23 @@
|
||||
"""Permission constants for the websocket API.
|
||||
|
||||
Separate file to avoid circular imports.
|
||||
"""
|
||||
from homeassistant.const import (
|
||||
EVENT_COMPONENT_LOADED,
|
||||
EVENT_SERVICE_REGISTERED,
|
||||
EVENT_SERVICE_REMOVED,
|
||||
EVENT_STATE_CHANGED,
|
||||
EVENT_THEMES_UPDATED)
|
||||
from homeassistant.components.persistent_notification import (
|
||||
EVENT_PERSISTENT_NOTIFICATIONS_UPDATED)
|
||||
|
||||
# These are events that do not contain any sensitive data
|
||||
# Except for state_changed, which is handled accordingly.
|
||||
SUBSCRIBE_WHITELIST = {
|
||||
EVENT_COMPONENT_LOADED,
|
||||
EVENT_PERSISTENT_NOTIFICATIONS_UPDATED,
|
||||
EVENT_SERVICE_REGISTERED,
|
||||
EVENT_SERVICE_REMOVED,
|
||||
EVENT_STATE_CHANGED,
|
||||
EVENT_THEMES_UPDATED,
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
"""Constants used by Home Assistant components."""
|
||||
MAJOR_VERSION = 0
|
||||
MINOR_VERSION = 90
|
||||
PATCH_VERSION = '0b4'
|
||||
PATCH_VERSION = '0'
|
||||
__short_version__ = '{}.{}'.format(MAJOR_VERSION, MINOR_VERSION)
|
||||
__version__ = '{}.{}'.format(__short_version__, PATCH_VERSION)
|
||||
REQUIRED_PYTHON_VER = (3, 5, 3)
|
||||
|
||||
@@ -524,7 +524,7 @@ habitipy==0.2.0
|
||||
hangups==0.4.6
|
||||
|
||||
# homeassistant.components.cloud
|
||||
hass-nabucasa==0.7
|
||||
hass-nabucasa==0.8
|
||||
|
||||
# homeassistant.components.mqtt.server
|
||||
hbmqtt==0.9.4
|
||||
@@ -554,7 +554,7 @@ hole==0.3.0
|
||||
holidays==0.9.9
|
||||
|
||||
# homeassistant.components.frontend
|
||||
home-assistant-frontend==20190316.0
|
||||
home-assistant-frontend==20190320.0
|
||||
|
||||
# homeassistant.components.zwave
|
||||
homeassistant-pyozw==0.1.2
|
||||
@@ -1394,7 +1394,7 @@ python-songpal==0.0.9.1
|
||||
python-synology==0.2.0
|
||||
|
||||
# homeassistant.components.tado
|
||||
python-tado==0.2.3
|
||||
python-tado==0.2.8
|
||||
|
||||
# homeassistant.components.telegram_bot
|
||||
python-telegram-bot==11.1.0
|
||||
@@ -1707,10 +1707,10 @@ tikteck==0.4
|
||||
todoist-python==7.0.17
|
||||
|
||||
# homeassistant.components.toon
|
||||
toonapilib==3.2.1
|
||||
toonapilib==3.2.2
|
||||
|
||||
# homeassistant.components.alarm_control_panel.totalconnect
|
||||
total_connect_client==0.22
|
||||
total_connect_client==0.24
|
||||
|
||||
# homeassistant.components.tplink_lte
|
||||
tp-connected==0.0.4
|
||||
|
||||
@@ -114,7 +114,7 @@ ha-ffmpeg==1.11
|
||||
hangups==0.4.6
|
||||
|
||||
# homeassistant.components.cloud
|
||||
hass-nabucasa==0.7
|
||||
hass-nabucasa==0.8
|
||||
|
||||
# homeassistant.components.mqtt.server
|
||||
hbmqtt==0.9.4
|
||||
@@ -126,7 +126,7 @@ hdate==0.8.7
|
||||
holidays==0.9.9
|
||||
|
||||
# homeassistant.components.frontend
|
||||
home-assistant-frontend==20190316.0
|
||||
home-assistant-frontend==20190320.0
|
||||
|
||||
# homeassistant.components.homekit_controller
|
||||
homekit[IP]==0.13.0
|
||||
@@ -298,7 +298,7 @@ srpenergy==1.0.5
|
||||
statsd==3.2.1
|
||||
|
||||
# homeassistant.components.toon
|
||||
toonapilib==3.2.1
|
||||
toonapilib==3.2.2
|
||||
|
||||
# homeassistant.components.camera.uvc
|
||||
uvcclient==0.11.0
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
"""The tests for the discovery component."""
|
||||
import asyncio
|
||||
import os
|
||||
from unittest.mock import patch, MagicMock
|
||||
|
||||
import pytest
|
||||
@@ -142,21 +141,6 @@ def test_discover_duplicates(hass):
|
||||
SERVICE_NO_PLATFORM_COMPONENT, BASE_CONFIG)
|
||||
|
||||
|
||||
@asyncio.coroutine
|
||||
def test_load_component_hassio(hass):
|
||||
"""Test load hassio component."""
|
||||
def discover(netdisco):
|
||||
"""Fake discovery."""
|
||||
return []
|
||||
|
||||
with patch.dict(os.environ, {'HASSIO': "FAKE_HASSIO"}), \
|
||||
patch('homeassistant.components.hassio.async_setup',
|
||||
return_value=mock_coro(return_value=True)) as mock_hassio:
|
||||
yield from mock_discovery(hass, discover)
|
||||
|
||||
assert mock_hassio.called
|
||||
|
||||
|
||||
async def test_discover_config_flow(hass):
|
||||
"""Test discovery triggering a config flow."""
|
||||
discovery_info = {
|
||||
|
||||
@@ -74,17 +74,6 @@ async def test_api_homeassistant_restart(hassio_handler, aioclient_mock):
|
||||
assert aioclient_mock.call_count == 1
|
||||
|
||||
|
||||
async def test_api_homeassistant_config(hassio_handler, aioclient_mock):
|
||||
"""Test setup with API HomeAssistant config."""
|
||||
aioclient_mock.post(
|
||||
"http://127.0.0.1/homeassistant/check", json={
|
||||
'result': 'ok', 'data': {'test': 'bla'}})
|
||||
|
||||
data = await hassio_handler.check_homeassistant_config()
|
||||
assert data['data']['test'] == 'bla'
|
||||
assert aioclient_mock.call_count == 1
|
||||
|
||||
|
||||
async def test_api_addon_info(hassio_handler, aioclient_mock):
|
||||
"""Test setup with API Add-on info."""
|
||||
aioclient_mock.get(
|
||||
|
||||
@@ -7,8 +7,7 @@ import pytest
|
||||
|
||||
from homeassistant.auth.const import GROUP_ID_ADMIN
|
||||
from homeassistant.setup import async_setup_component
|
||||
from homeassistant.components.hassio import (
|
||||
STORAGE_KEY, async_check_config)
|
||||
from homeassistant.components.hassio import STORAGE_KEY
|
||||
|
||||
from tests.common import mock_coro
|
||||
|
||||
@@ -311,8 +310,6 @@ def test_service_calls_core(hassio_env, hass, aioclient_mock):
|
||||
"http://127.0.0.1/homeassistant/restart", json={'result': 'ok'})
|
||||
aioclient_mock.post(
|
||||
"http://127.0.0.1/homeassistant/stop", json={'result': 'ok'})
|
||||
aioclient_mock.post(
|
||||
"http://127.0.0.1/homeassistant/check", json={'result': 'ok'})
|
||||
|
||||
yield from hass.services.async_call('homeassistant', 'stop')
|
||||
yield from hass.async_block_till_done()
|
||||
@@ -322,32 +319,14 @@ def test_service_calls_core(hassio_env, hass, aioclient_mock):
|
||||
yield from hass.services.async_call('homeassistant', 'check_config')
|
||||
yield from hass.async_block_till_done()
|
||||
|
||||
assert aioclient_mock.call_count == 2
|
||||
|
||||
with patch(
|
||||
'homeassistant.config.async_check_ha_config_file',
|
||||
return_value=mock_coro()
|
||||
) as mock_check_config:
|
||||
yield from hass.services.async_call('homeassistant', 'restart')
|
||||
yield from hass.async_block_till_done()
|
||||
assert mock_check_config.called
|
||||
|
||||
assert aioclient_mock.call_count == 3
|
||||
|
||||
yield from hass.services.async_call('homeassistant', 'restart')
|
||||
yield from hass.async_block_till_done()
|
||||
|
||||
assert aioclient_mock.call_count == 5
|
||||
|
||||
|
||||
@asyncio.coroutine
|
||||
def test_check_config_ok(hassio_env, hass, aioclient_mock):
|
||||
"""Check Config that is okay."""
|
||||
assert (yield from async_setup_component(hass, 'hassio', {}))
|
||||
|
||||
aioclient_mock.post(
|
||||
"http://127.0.0.1/homeassistant/check", json={'result': 'ok'})
|
||||
|
||||
assert (yield from async_check_config(hass)) is None
|
||||
|
||||
|
||||
@asyncio.coroutine
|
||||
def test_check_config_fail(hassio_env, hass, aioclient_mock):
|
||||
"""Check Config that is wrong."""
|
||||
assert (yield from async_setup_component(hass, 'hassio', {}))
|
||||
|
||||
aioclient_mock.post(
|
||||
"http://127.0.0.1/homeassistant/check", json={
|
||||
'result': 'error', 'message': "Error"})
|
||||
|
||||
assert (yield from async_check_config(hass)) == "Error"
|
||||
|
||||
@@ -333,3 +333,76 @@ async def test_get_states_not_allows_nan(hass, websocket_client):
|
||||
msg = await websocket_client.receive_json()
|
||||
assert not msg['success']
|
||||
assert msg['error']['code'] == const.ERR_UNKNOWN_ERROR
|
||||
|
||||
|
||||
async def test_subscribe_unsubscribe_events_whitelist(
|
||||
hass, websocket_client, hass_admin_user):
|
||||
"""Test subscribe/unsubscribe events on whitelist."""
|
||||
hass_admin_user.groups = []
|
||||
|
||||
await websocket_client.send_json({
|
||||
'id': 5,
|
||||
'type': 'subscribe_events',
|
||||
'event_type': 'not-in-whitelist'
|
||||
})
|
||||
|
||||
msg = await websocket_client.receive_json()
|
||||
assert msg['id'] == 5
|
||||
assert msg['type'] == const.TYPE_RESULT
|
||||
assert not msg['success']
|
||||
assert msg['error']['code'] == 'unauthorized'
|
||||
|
||||
await websocket_client.send_json({
|
||||
'id': 6,
|
||||
'type': 'subscribe_events',
|
||||
'event_type': 'themes_updated'
|
||||
})
|
||||
|
||||
msg = await websocket_client.receive_json()
|
||||
assert msg['id'] == 6
|
||||
assert msg['type'] == const.TYPE_RESULT
|
||||
assert msg['success']
|
||||
|
||||
hass.bus.async_fire('themes_updated')
|
||||
|
||||
with timeout(3, loop=hass.loop):
|
||||
msg = await websocket_client.receive_json()
|
||||
|
||||
assert msg['id'] == 6
|
||||
assert msg['type'] == 'event'
|
||||
event = msg['event']
|
||||
assert event['event_type'] == 'themes_updated'
|
||||
assert event['origin'] == 'LOCAL'
|
||||
|
||||
|
||||
async def test_subscribe_unsubscribe_events_state_changed(
|
||||
hass, websocket_client, hass_admin_user):
|
||||
"""Test subscribe/unsubscribe state_changed events."""
|
||||
hass_admin_user.groups = []
|
||||
hass_admin_user.mock_policy({
|
||||
'entities': {
|
||||
'entity_ids': {
|
||||
'light.permitted': True
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
await websocket_client.send_json({
|
||||
'id': 7,
|
||||
'type': 'subscribe_events',
|
||||
'event_type': 'state_changed'
|
||||
})
|
||||
|
||||
msg = await websocket_client.receive_json()
|
||||
assert msg['id'] == 7
|
||||
assert msg['type'] == const.TYPE_RESULT
|
||||
assert msg['success']
|
||||
|
||||
hass.states.async_set('light.not_permitted', 'on')
|
||||
hass.states.async_set('light.permitted', 'on')
|
||||
|
||||
msg = await websocket_client.receive_json()
|
||||
assert msg['id'] == 7
|
||||
assert msg['type'] == 'event'
|
||||
assert msg['event']['event_type'] == 'state_changed'
|
||||
assert msg['event']['data']['entity_id'] == 'light.permitted'
|
||||
|
||||
@@ -34,7 +34,7 @@ def test_from_config_file(hass):
|
||||
}
|
||||
|
||||
with patch_yaml_files(files, True):
|
||||
yield from bootstrap.async_from_config_file('config.yaml')
|
||||
yield from bootstrap.async_from_config_file('config.yaml', hass)
|
||||
|
||||
assert components == hass.config.components
|
||||
|
||||
@@ -103,3 +103,12 @@ async def test_async_from_config_file_not_mount_deps_folder(loop):
|
||||
|
||||
await bootstrap.async_from_config_file('mock-path', hass)
|
||||
assert len(mock_mount.mock_calls) == 0
|
||||
|
||||
|
||||
async def test_load_hassio(hass):
|
||||
"""Test that we load Hass.io component."""
|
||||
with patch.dict(os.environ, {}, clear=True):
|
||||
assert bootstrap._get_components(hass, {}) == set()
|
||||
|
||||
with patch.dict(os.environ, {'HASSIO': '1'}):
|
||||
assert bootstrap._get_components(hass, {}) == {'hassio'}
|
||||
|
||||
Reference in New Issue
Block a user