Merge pull request #12334 from home-assistant/release-0-63-1

0.63.1
This commit is contained in:
Paulus Schoutsen 2018-02-12 08:56:04 -08:00 committed by GitHub
commit 073126755c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 210 additions and 55 deletions

View File

@ -328,8 +328,9 @@ class _AlexaBrightnessController(_AlexaInterface):
def get_property(self, name): def get_property(self, name):
if name != 'brightness': if name != 'brightness':
raise _UnsupportedProperty(name) raise _UnsupportedProperty(name)
if 'brightness' in self.entity.attributes:
return round(self.entity.attributes['brightness'] / 255.0 * 100) return round(self.entity.attributes['brightness'] / 255.0 * 100)
return 0
class _AlexaColorController(_AlexaInterface): class _AlexaColorController(_AlexaInterface):
@ -1064,7 +1065,16 @@ def async_api_lock(hass, config, request, entity):
ATTR_ENTITY_ID: entity.entity_id ATTR_ENTITY_ID: entity.entity_id
}, blocking=False) }, blocking=False)
return api_message(request) # Alexa expects a lockState in the response, we don't know the actual
# lockState at this point but assume it is locked. It is reported
# correctly later when ReportState is called. The alt. to this approach
# is to implement DeferredResponse
properties = [{
'name': 'lockState',
'namespace': 'Alexa.LockController',
'value': 'LOCKED'
}]
return api_message(request, context={'properties': properties})
# Not supported by Alexa yet # Not supported by Alexa yet
@ -1168,7 +1178,7 @@ def async_api_adjust_volume(hass, config, request, entity):
@asyncio.coroutine @asyncio.coroutine
def async_api_adjust_volume_step(hass, config, request, entity): def async_api_adjust_volume_step(hass, config, request, entity):
"""Process an adjust volume step request.""" """Process an adjust volume step request."""
volume_step = round(float(request[API_PAYLOAD]['volume'] / 100), 2) volume_step = round(float(request[API_PAYLOAD]['volumeSteps'] / 100), 2)
current_level = entity.attributes.get(media_player.ATTR_MEDIA_VOLUME_LEVEL) current_level = entity.attributes.get(media_player.ATTR_MEDIA_VOLUME_LEVEL)

View File

@ -131,8 +131,6 @@ class NetatmoBinarySensor(BinarySensorDevice):
self._name += ' / ' + module_name self._name += ' / ' + module_name
self._sensor_name = sensor self._sensor_name = sensor
self._name += ' ' + sensor self._name += ' ' + sensor
self._unique_id = data.camera_data.cameraByName(
camera=camera_name, home=home)['id']
self._cameratype = camera_type self._cameratype = camera_type
self._state = None self._state = None
@ -141,11 +139,6 @@ class NetatmoBinarySensor(BinarySensorDevice):
"""Return the name of the Netatmo device and this sensor.""" """Return the name of the Netatmo device and this sensor."""
return self._name return self._name
@property
def unique_id(self):
"""Return the unique ID for this sensor."""
return self._unique_id
@property @property
def device_class(self): def device_class(self):
"""Return the class of this sensor, from DEVICE_CLASSES.""" """Return the class of this sensor, from DEVICE_CLASSES."""

View File

@ -67,8 +67,6 @@ class NetatmoCamera(Camera):
self._vpnurl, self._localurl = self._data.camera_data.cameraUrls( self._vpnurl, self._localurl = self._data.camera_data.cameraUrls(
camera=camera_name camera=camera_name
) )
self._unique_id = data.camera_data.cameraByName(
camera=camera_name, home=home)['id']
self._cameratype = camera_type self._cameratype = camera_type
def camera_image(self): def camera_image(self):
@ -112,8 +110,3 @@ class NetatmoCamera(Camera):
elif self._cameratype == "NACamera": elif self._cameratype == "NACamera":
return "Welcome" return "Welcome"
return None return None
@property
def unique_id(self):
"""Return the unique ID for this camera."""
return self._unique_id

View File

@ -226,7 +226,6 @@ class XiaomiMiioRemote(RemoteDevice):
_LOGGER.error("Device does not support turn_off, " + _LOGGER.error("Device does not support turn_off, " +
"please use 'remote.send_command' to send commands.") "please use 'remote.send_command' to send commands.")
# pylint: enable=R0201
def _send_command(self, payload): def _send_command(self, payload):
"""Send a command.""" """Send a command."""
from miio import DeviceException from miio import DeviceException

View File

@ -113,18 +113,12 @@ class NetAtmoSensor(Entity):
module_id = self.netatmo_data.\ module_id = self.netatmo_data.\
station_data.moduleByName(module=module_name)['_id'] station_data.moduleByName(module=module_name)['_id']
self.module_id = module_id[1] self.module_id = module_id[1]
self._unique_id = '{}-{}'.format(self.module_id, self.type)
@property @property
def name(self): def name(self):
"""Return the name of the sensor.""" """Return the name of the sensor."""
return self._name return self._name
@property
def unique_id(self):
"""Return the unique ID for this sensor."""
return self._unique_id
@property @property
def icon(self): def icon(self):
"""Icon to use in the frontend, if any.""" """Icon to use in the frontend, if any."""

View File

@ -18,7 +18,7 @@ from homeassistant.util import slugify
REQUIREMENTS = [ REQUIREMENTS = [
'bellows==0.5.0', 'bellows==0.5.0',
'zigpy==0.0.1', 'zigpy==0.0.1',
'zigpy-xbee==0.0.1', 'zigpy-xbee==0.0.2',
] ]
DOMAIN = 'zha' DOMAIN = 'zha'

View File

@ -2,7 +2,7 @@
"""Constants used by Home Assistant components.""" """Constants used by Home Assistant components."""
MAJOR_VERSION = 0 MAJOR_VERSION = 0
MINOR_VERSION = 63 MINOR_VERSION = 63
PATCH_VERSION = '0' PATCH_VERSION = '1'
__short_version__ = '{}.{}'.format(MAJOR_VERSION, MINOR_VERSION) __short_version__ = '{}.{}'.format(MAJOR_VERSION, MINOR_VERSION)
__version__ = '{}.{}'.format(__short_version__, PATCH_VERSION) __version__ = '{}.{}'.format(__short_version__, PATCH_VERSION)
REQUIRED_PYTHON_VER = (3, 4, 2) REQUIRED_PYTHON_VER = (3, 4, 2)

View File

@ -80,6 +80,9 @@ class Entity(object):
# Process updates in parallel # Process updates in parallel
parallel_updates = None parallel_updates = None
# Name in the entity registry
registry_name = None
@property @property
def should_poll(self) -> bool: def should_poll(self) -> bool:
"""Return True if entity has to be polled for state. """Return True if entity has to be polled for state.
@ -225,7 +228,7 @@ class Entity(object):
if unit_of_measurement is not None: if unit_of_measurement is not None:
attr[ATTR_UNIT_OF_MEASUREMENT] = unit_of_measurement attr[ATTR_UNIT_OF_MEASUREMENT] = unit_of_measurement
name = self.name name = self.registry_name or self.name
if name is not None: if name is not None:
attr[ATTR_FRIENDLY_NAME] = name attr[ATTR_FRIENDLY_NAME] = name

View File

@ -40,19 +40,19 @@ class EntityComponent(object):
self.config = None self.config = None
self._platforms = { self._platforms = {
'core': EntityPlatform( domain: EntityPlatform(
hass=hass, hass=hass,
logger=logger, logger=logger,
domain=domain, domain=domain,
platform_name='core', platform_name=domain,
scan_interval=self.scan_interval, scan_interval=self.scan_interval,
parallel_updates=0, parallel_updates=0,
entity_namespace=None, entity_namespace=None,
async_entities_added_callback=self._async_update_group, async_entities_added_callback=self._async_update_group,
) )
} }
self.async_add_entities = self._platforms['core'].async_add_entities self.async_add_entities = self._platforms[domain].async_add_entities
self.add_entities = self._platforms['core'].add_entities self.add_entities = self._platforms[domain].add_entities
@property @property
def entities(self): def entities(self):
@ -190,7 +190,7 @@ class EntityComponent(object):
yield from asyncio.wait(tasks, loop=self.hass.loop) yield from asyncio.wait(tasks, loop=self.hass.loop)
self._platforms = { self._platforms = {
'core': self._platforms['core'] self.domain: self._platforms[self.domain]
} }
self.config = None self.config = None

View File

@ -209,10 +209,15 @@ class EntityPlatform(object):
else: else:
suggested_object_id = entity.name suggested_object_id = entity.name
if self.entity_namespace is not None:
suggested_object_id = '{} {}'.format(
self.entity_namespace, suggested_object_id)
entry = registry.async_get_or_create( entry = registry.async_get_or_create(
self.domain, self.platform_name, entity.unique_id, self.domain, self.platform_name, entity.unique_id,
suggested_object_id=suggested_object_id) suggested_object_id=suggested_object_id)
entity.entity_id = entry.entity_id entity.entity_id = entry.entity_id
entity.registry_name = entry.name
# We won't generate an entity ID if the platform has already set one # We won't generate an entity ID if the platform has already set one
# We will however make sure that platform cannot pick a registered ID # We will however make sure that platform cannot pick a registered ID
@ -239,8 +244,12 @@ class EntityPlatform(object):
raise HomeAssistantError( raise HomeAssistantError(
'Invalid entity id: {}'.format(entity.entity_id)) 'Invalid entity id: {}'.format(entity.entity_id))
elif entity.entity_id in component_entities: elif entity.entity_id in component_entities:
msg = 'Entity id already exists: {}'.format(entity.entity_id)
if entity.unique_id is not None:
msg += '. Platform {} does not generate unique IDs'.format(
self.platform_name)
raise HomeAssistantError( raise HomeAssistantError(
'Entity id already exists: {}'.format(entity.entity_id)) msg)
self.entities[entity.entity_id] = entity self.entities[entity.entity_id] = entity
component_entities.add(entity.entity_id) component_entities.add(entity.entity_id)

View File

@ -11,22 +11,37 @@ After initializing, call EntityRegistry.async_ensure_loaded to load the data
from disk. from disk.
""" """
import asyncio import asyncio
from collections import namedtuple, OrderedDict from collections import OrderedDict
from itertools import chain from itertools import chain
import logging import logging
import os import os
import attr
from ..core import callback, split_entity_id from ..core import callback, split_entity_id
from ..util import ensure_unique_string, slugify from ..util import ensure_unique_string, slugify
from ..util.yaml import load_yaml, save_yaml from ..util.yaml import load_yaml, save_yaml
PATH_REGISTRY = 'entity_registry.yaml' PATH_REGISTRY = 'entity_registry.yaml'
SAVE_DELAY = 10 SAVE_DELAY = 10
Entry = namedtuple('EntityRegistryEntry',
'entity_id,unique_id,platform,domain')
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@attr.s(slots=True, frozen=True)
class RegistryEntry:
"""Entity Registry Entry."""
entity_id = attr.ib(type=str)
unique_id = attr.ib(type=str)
platform = attr.ib(type=str)
name = attr.ib(type=str, default=None)
domain = attr.ib(type=str, default=None, init=False, repr=False)
def __attrs_post_init__(self):
"""Computed properties."""
object.__setattr__(self, "domain", split_entity_id(self.entity_id)[0])
class EntityRegistry: class EntityRegistry:
"""Class to hold a registry of entities.""" """Class to hold a registry of entities."""
@ -65,11 +80,10 @@ class EntityRegistry:
entity_id = self.async_generate_entity_id( entity_id = self.async_generate_entity_id(
domain, suggested_object_id or '{}_{}'.format(platform, unique_id)) domain, suggested_object_id or '{}_{}'.format(platform, unique_id))
entity = Entry( entity = RegistryEntry(
entity_id=entity_id, entity_id=entity_id,
unique_id=unique_id, unique_id=unique_id,
platform=platform, platform=platform,
domain=domain,
) )
self.entities[entity_id] = entity self.entities[entity_id] = entity
_LOGGER.info('Registered new %s.%s entity: %s', _LOGGER.info('Registered new %s.%s entity: %s',
@ -98,11 +112,11 @@ class EntityRegistry:
data = yield from self.hass.async_add_job(load_yaml, path) data = yield from self.hass.async_add_job(load_yaml, path)
for entity_id, info in data.items(): for entity_id, info in data.items():
entities[entity_id] = Entry( entities[entity_id] = RegistryEntry(
domain=split_entity_id(entity_id)[0],
entity_id=entity_id, entity_id=entity_id,
unique_id=info['unique_id'], unique_id=info['unique_id'],
platform=info['platform'] platform=info['platform'],
name=info.get('name')
) )
self.entities = entities self.entities = entities

View File

@ -11,6 +11,7 @@ async_timeout==2.0.0
chardet==3.0.4 chardet==3.0.4
astral==1.5 astral==1.5
certifi>=2017.4.17 certifi>=2017.4.17
attrs==17.4.0
# Breaks Python 3.6 and is not needed for our supported Pythons # Breaks Python 3.6 and is not needed for our supported Pythons
enum34==1000000000.0.0 enum34==1000000000.0.0

View File

@ -206,7 +206,7 @@ def async_prepare_setup_platform(hass: core.HomeAssistant, config, domain: str,
return platform return platform
try: try:
yield from _process_deps_reqs(hass, config, platform_name, platform) yield from _process_deps_reqs(hass, config, platform_path, platform)
except HomeAssistantError as err: except HomeAssistantError as err:
log_error(str(err)) log_error(str(err))
return None return None

View File

@ -12,6 +12,7 @@ async_timeout==2.0.0
chardet==3.0.4 chardet==3.0.4
astral==1.5 astral==1.5
certifi>=2017.4.17 certifi>=2017.4.17
attrs==17.4.0
# homeassistant.components.nuimo_controller # homeassistant.components.nuimo_controller
--only-binary=all https://github.com/getSenic/nuimo-linux-python/archive/29fc42987f74d8090d0e2382e8f248ff5990b8c9.zip#nuimo==1.0.0 --only-binary=all https://github.com/getSenic/nuimo-linux-python/archive/29fc42987f74d8090d0e2382e8f248ff5990b8c9.zip#nuimo==1.0.0
@ -1275,7 +1276,7 @@ zeroconf==0.19.1
ziggo-mediabox-xl==1.0.0 ziggo-mediabox-xl==1.0.0
# homeassistant.components.zha # homeassistant.components.zha
zigpy-xbee==0.0.1 zigpy-xbee==0.0.2
# homeassistant.components.zha # homeassistant.components.zha
zigpy==0.0.1 zigpy==0.0.1

View File

@ -61,6 +61,7 @@ REQUIRES = [
'chardet==3.0.4', 'chardet==3.0.4',
'astral==1.5', 'astral==1.5',
'certifi>=2017.4.17', 'certifi>=2017.4.17',
'attrs==17.4.0',
] ]
MIN_PY_VERSION = '.'.join(map( MIN_PY_VERSION = '.'.join(map(

View File

@ -317,10 +317,10 @@ def mock_component(hass, component):
hass.config.components.add(component) hass.config.components.add(component)
def mock_registry(hass): def mock_registry(hass, mock_entries=None):
"""Mock the Entity Registry.""" """Mock the Entity Registry."""
registry = entity_registry.EntityRegistry(hass) registry = entity_registry.EntityRegistry(hass)
registry.entities = {} registry.entities = mock_entries or {}
hass.data[entity_platform.DATA_REGISTRY] = registry hass.data[entity_platform.DATA_REGISTRY] = registry
return registry return registry

View File

@ -401,11 +401,17 @@ def test_lock(hass):
assert appliance['friendlyName'] == "Test lock" assert appliance['friendlyName'] == "Test lock"
assert_endpoint_capabilities(appliance, 'Alexa.LockController') assert_endpoint_capabilities(appliance, 'Alexa.LockController')
yield from assert_request_calls_service( _, msg = yield from assert_request_calls_service(
'Alexa.LockController', 'Lock', 'lock#test', 'Alexa.LockController', 'Lock', 'lock#test',
'lock.lock', 'lock.lock',
hass) hass)
# always return LOCKED for now
properties = msg['context']['properties'][0]
assert properties['name'] == 'lockState'
assert properties['namespace'] == 'Alexa.LockController'
assert properties['value'] == 'LOCKED'
@asyncio.coroutine @asyncio.coroutine
def test_media_player(hass): def test_media_player(hass):
@ -511,14 +517,14 @@ def test_media_player(hass):
'Alexa.StepSpeaker', 'AdjustVolume', 'media_player#test', 'Alexa.StepSpeaker', 'AdjustVolume', 'media_player#test',
'media_player.volume_set', 'media_player.volume_set',
hass, hass,
payload={'volume': 20}) payload={'volumeSteps': 20})
assert call.data['volume_level'] == 0.95 assert call.data['volume_level'] == 0.95
call, _ = yield from assert_request_calls_service( call, _ = yield from assert_request_calls_service(
'Alexa.StepSpeaker', 'AdjustVolume', 'media_player#test', 'Alexa.StepSpeaker', 'AdjustVolume', 'media_player#test',
'media_player.volume_set', 'media_player.volume_set',
hass, hass,
payload={'volume': -20}) payload={'volumeSteps': -20})
assert call.data['volume_level'] == 0.55 assert call.data['volume_level'] == 0.55
@ -1095,6 +1101,23 @@ def test_report_lock_state(hass):
properties.assert_equal('Alexa.LockController', 'lockState', 'JAMMED') properties.assert_equal('Alexa.LockController', 'lockState', 'JAMMED')
@asyncio.coroutine
def test_report_dimmable_light_state(hass):
"""Test BrightnessController reports brightness correctly."""
hass.states.async_set(
'light.test_on', 'on', {'friendly_name': "Test light On",
'brightness': 128, 'supported_features': 1})
hass.states.async_set(
'light.test_off', 'off', {'friendly_name': "Test light Off",
'supported_features': 1})
properties = yield from reported_properties(hass, 'light.test_on')
properties.assert_equal('Alexa.BrightnessController', 'brightness', 50)
properties = yield from reported_properties(hass, 'light.test_off')
properties.assert_equal('Alexa.BrightnessController', 'brightness', 0)
@asyncio.coroutine @asyncio.coroutine
def reported_properties(hass, endpoint): def reported_properties(hass, endpoint):
"""Use ReportState to get properties and return them. """Use ReportState to get properties and return them.
@ -1118,7 +1141,7 @@ class _ReportedProperties(object):
for prop in self.properties: for prop in self.properties:
if prop['namespace'] == namespace and prop['name'] == name: if prop['namespace'] == namespace and prop['name'] == name:
assert prop['value'] == value assert prop['value'] == value
return prop return prop
assert False, 'property %s:%s not in %r' % ( assert False, 'property %s:%s not in %r' % (
namespace, namespace,

View File

@ -12,7 +12,7 @@ import homeassistant.loader as loader
from homeassistant.exceptions import PlatformNotReady from homeassistant.exceptions import PlatformNotReady
from homeassistant.components import group from homeassistant.components import group
from homeassistant.helpers.entity_component import EntityComponent from homeassistant.helpers.entity_component import EntityComponent
from homeassistant.setup import setup_component from homeassistant.setup import setup_component, async_setup_component
from homeassistant.helpers import discovery from homeassistant.helpers import discovery
import homeassistant.util.dt as dt_util import homeassistant.util.dt as dt_util
@ -305,3 +305,31 @@ def test_extract_from_service_no_group_expand(hass):
extracted = component.async_extract_from_service(call, expand_group=False) extracted = component.async_extract_from_service(call, expand_group=False)
assert extracted == [test_group] assert extracted == [test_group]
@asyncio.coroutine
def test_setup_dependencies_platform(hass):
"""Test we setup the dependencies of a platform.
We're explictely testing that we process dependencies even if a component
with the same name has already been loaded.
"""
loader.set_component('test_component', MockModule('test_component'))
loader.set_component('test_component2', MockModule('test_component2'))
loader.set_component(
'test_domain.test_component',
MockPlatform(dependencies=['test_component', 'test_component2']))
component = EntityComponent(_LOGGER, DOMAIN, hass)
yield from async_setup_component(hass, 'test_component', {})
yield from component.async_setup({
DOMAIN: {
'platform': 'test_component',
}
})
assert 'test_component' in hass.config.components
assert 'test_component2' in hass.config.components
assert 'test_domain.test_component' in hass.config.components

View File

@ -9,7 +9,7 @@ import homeassistant.loader as loader
from homeassistant.helpers.entity import generate_entity_id from homeassistant.helpers.entity import generate_entity_id
from homeassistant.helpers.entity_component import ( from homeassistant.helpers.entity_component import (
EntityComponent, DEFAULT_SCAN_INTERVAL) EntityComponent, DEFAULT_SCAN_INTERVAL)
from homeassistant.helpers import entity_platform from homeassistant.helpers import entity_platform, entity_registry
import homeassistant.util.dt as dt_util import homeassistant.util.dt as dt_util
@ -21,6 +21,32 @@ _LOGGER = logging.getLogger(__name__)
DOMAIN = "test_domain" DOMAIN = "test_domain"
class MockEntityPlatform(entity_platform.EntityPlatform):
"""Mock class with some mock defaults."""
def __init__(
self, *, hass,
logger=None,
domain='test',
platform_name='test_platform',
scan_interval=timedelta(seconds=15),
parallel_updates=0,
entity_namespace=None,
async_entities_added_callback=lambda: None
):
"""Initialize a mock entity platform."""
super().__init__(
hass=hass,
logger=logger,
domain=domain,
platform_name=platform_name,
scan_interval=scan_interval,
parallel_updates=parallel_updates,
entity_namespace=entity_namespace,
async_entities_added_callback=async_entities_added_callback,
)
class TestHelpersEntityPlatform(unittest.TestCase): class TestHelpersEntityPlatform(unittest.TestCase):
"""Test homeassistant.helpers.entity_component module.""" """Test homeassistant.helpers.entity_component module."""
@ -433,3 +459,34 @@ def test_entity_with_name_and_entity_id_getting_registered(hass):
MockEntity(unique_id='1234', name='bla', MockEntity(unique_id='1234', name='bla',
entity_id='test_domain.world')]) entity_id='test_domain.world')])
assert 'test_domain.world' in hass.states.async_entity_ids() assert 'test_domain.world' in hass.states.async_entity_ids()
@asyncio.coroutine
def test_overriding_name_from_registry(hass):
"""Test that we can override a name via the Entity Registry."""
component = EntityComponent(_LOGGER, DOMAIN, hass)
mock_registry(hass, {
'test_domain.world': entity_registry.RegistryEntry(
entity_id='test_domain.world',
unique_id='1234',
# Using component.async_add_entities is equal to platform "domain"
platform='test_domain',
name='Overridden'
)
})
yield from component.async_add_entities([
MockEntity(unique_id='1234', name='Device Name')])
state = hass.states.get('test_domain.world')
assert state is not None
assert state.name == 'Overridden'
@asyncio.coroutine
def test_registry_respect_entity_namespace(hass):
"""Test that the registry respects entity namespace."""
mock_registry(hass)
platform = MockEntityPlatform(hass=hass, entity_namespace='ns')
entity = MockEntity(unique_id='1234', name='Device Name')
yield from platform.async_add_entities([entity])
assert entity.entity_id == 'test.ns_device_name'

View File

@ -9,6 +9,9 @@ from homeassistant.helpers import entity_registry
from tests.common import mock_registry from tests.common import mock_registry
YAML__OPEN_PATH = 'homeassistant.util.yaml.open'
@pytest.fixture @pytest.fixture
def registry(hass): def registry(hass):
"""Return an empty, loaded, registry.""" """Return an empty, loaded, registry."""
@ -82,13 +85,12 @@ def test_save_timer_reset_on_subsequent_save(hass, registry):
@asyncio.coroutine @asyncio.coroutine
def test_loading_saving_data(hass, registry): def test_loading_saving_data(hass, registry):
"""Test that we load/save data correctly.""" """Test that we load/save data correctly."""
yaml_path = 'homeassistant.util.yaml.open'
orig_entry1 = registry.async_get_or_create('light', 'hue', '1234') orig_entry1 = registry.async_get_or_create('light', 'hue', '1234')
orig_entry2 = registry.async_get_or_create('light', 'hue', '5678') orig_entry2 = registry.async_get_or_create('light', 'hue', '5678')
assert len(registry.entities) == 2 assert len(registry.entities) == 2
with patch(yaml_path, mock_open(), create=True) as mock_write: with patch(YAML__OPEN_PATH, mock_open(), create=True) as mock_write:
yield from registry._async_save() yield from registry._async_save()
# Mock open calls are: open file, context enter, write, context leave # Mock open calls are: open file, context enter, write, context leave
@ -98,7 +100,7 @@ def test_loading_saving_data(hass, registry):
registry2 = entity_registry.EntityRegistry(hass) registry2 = entity_registry.EntityRegistry(hass)
with patch('os.path.isfile', return_value=True), \ with patch('os.path.isfile', return_value=True), \
patch(yaml_path, mock_open(read_data=written), create=True): patch(YAML__OPEN_PATH, mock_open(read_data=written), create=True):
yield from registry2._async_load() yield from registry2._async_load()
# Ensure same order # Ensure same order
@ -133,3 +135,30 @@ def test_is_registered(registry):
entry = registry.async_get_or_create('light', 'hue', '1234') entry = registry.async_get_or_create('light', 'hue', '1234')
assert registry.async_is_registered(entry.entity_id) assert registry.async_is_registered(entry.entity_id)
assert not registry.async_is_registered('light.non_existing') assert not registry.async_is_registered('light.non_existing')
@asyncio.coroutine
def test_loading_extra_values(hass):
"""Test we load extra data from the registry."""
written = """
test.named:
platform: super_platform
unique_id: with-name
name: registry override
test.no_name:
platform: super_platform
unique_id: without-name
"""
registry = entity_registry.EntityRegistry(hass)
with patch('os.path.isfile', return_value=True), \
patch(YAML__OPEN_PATH, mock_open(read_data=written), create=True):
yield from registry._async_load()
entry_with_name = registry.async_get_or_create(
'test', 'super_platform', 'with-name')
entry_without_name = registry.async_get_or_create(
'test', 'super_platform', 'without-name')
assert entry_with_name.name == 'registry override'
assert entry_without_name.name is None