Simplify customize (#6007)
* Simplify customize * Maintain glob order * Have glob overrule domainpull/6037/head
parent
eb9400de4c
commit
235d0057b1
|
@ -13,9 +13,9 @@ import voluptuous as vol
|
|||
|
||||
from homeassistant.const import (
|
||||
CONF_LATITUDE, CONF_LONGITUDE, CONF_NAME, CONF_PACKAGES, CONF_UNIT_SYSTEM,
|
||||
CONF_TIME_ZONE, CONF_CUSTOMIZE, CONF_ELEVATION, CONF_UNIT_SYSTEM_METRIC,
|
||||
CONF_TIME_ZONE, CONF_ELEVATION, CONF_UNIT_SYSTEM_METRIC,
|
||||
CONF_UNIT_SYSTEM_IMPERIAL, CONF_TEMPERATURE_UNIT, TEMP_CELSIUS,
|
||||
__version__)
|
||||
__version__, CONF_CUSTOMIZE, CONF_CUSTOMIZE_DOMAIN, CONF_CUSTOMIZE_GLOB)
|
||||
from homeassistant.core import DOMAIN as CONF_CORE
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
from homeassistant.loader import get_component
|
||||
|
@ -23,13 +23,14 @@ from homeassistant.util.yaml import load_yaml
|
|||
import homeassistant.helpers.config_validation as cv
|
||||
from homeassistant.util import dt as date_util, location as loc_util
|
||||
from homeassistant.util.unit_system import IMPERIAL_SYSTEM, METRIC_SYSTEM
|
||||
from homeassistant.helpers import customize
|
||||
from homeassistant.helpers.entity_values import EntityValues
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
YAML_CONFIG_FILE = 'configuration.yaml'
|
||||
VERSION_FILE = '.HA_VERSION'
|
||||
CONFIG_DIR_NAME = '.homeassistant'
|
||||
DATA_CUSTOMIZE = 'hass_customize'
|
||||
|
||||
DEFAULT_CORE_CONFIG = (
|
||||
# Tuples (attribute, default, auto detect property, description)
|
||||
|
@ -96,7 +97,16 @@ PACKAGES_CONFIG_SCHEMA = vol.Schema({
|
|||
{cv.slug: vol.Any(dict, list)}) # Only slugs for component names
|
||||
})
|
||||
|
||||
CORE_CONFIG_SCHEMA = vol.Schema({
|
||||
CUSTOMIZE_CONFIG_SCHEMA = vol.Schema({
|
||||
vol.Optional(CONF_CUSTOMIZE, default={}):
|
||||
vol.Schema({cv.entity_id: dict}),
|
||||
vol.Optional(CONF_CUSTOMIZE_DOMAIN, default={}):
|
||||
vol.Schema({cv.string: dict}),
|
||||
vol.Optional(CONF_CUSTOMIZE_GLOB, default={}):
|
||||
vol.Schema({cv.string: dict}),
|
||||
})
|
||||
|
||||
CORE_CONFIG_SCHEMA = CUSTOMIZE_CONFIG_SCHEMA.extend({
|
||||
CONF_NAME: vol.Coerce(str),
|
||||
CONF_LATITUDE: cv.latitude,
|
||||
CONF_LONGITUDE: cv.longitude,
|
||||
|
@ -104,7 +114,6 @@ CORE_CONFIG_SCHEMA = vol.Schema({
|
|||
vol.Optional(CONF_TEMPERATURE_UNIT): cv.temperature_unit,
|
||||
CONF_UNIT_SYSTEM: cv.unit_system,
|
||||
CONF_TIME_ZONE: cv.time_zone,
|
||||
vol.Optional(CONF_CUSTOMIZE, default=[]): customize.CUSTOMIZE_SCHEMA,
|
||||
vol.Optional(CONF_PACKAGES, default={}): PACKAGES_CONFIG_SCHEMA,
|
||||
})
|
||||
|
||||
|
@ -289,9 +298,29 @@ def async_process_ha_core_config(hass, config):
|
|||
if CONF_TIME_ZONE in config:
|
||||
set_time_zone(config.get(CONF_TIME_ZONE))
|
||||
|
||||
merged_customize = merge_packages_customize(
|
||||
config[CONF_CUSTOMIZE], config[CONF_PACKAGES])
|
||||
customize.set_customize(hass, CONF_CORE, merged_customize)
|
||||
# Customize
|
||||
cust_exact = dict(config[CONF_CUSTOMIZE])
|
||||
cust_domain = dict(config[CONF_CUSTOMIZE_DOMAIN])
|
||||
cust_glob = dict(config[CONF_CUSTOMIZE_GLOB])
|
||||
|
||||
for name, pkg in config[CONF_PACKAGES].items():
|
||||
pkg_cust = pkg.get(CONF_CORE)
|
||||
|
||||
if pkg_cust is None:
|
||||
continue
|
||||
|
||||
try:
|
||||
pkg_cust = CUSTOMIZE_CONFIG_SCHEMA(pkg_cust)
|
||||
except vol.Invalid:
|
||||
_LOGGER.warning('Package %s contains invalid customize', name)
|
||||
continue
|
||||
|
||||
cust_exact.update(pkg_cust[CONF_CUSTOMIZE])
|
||||
cust_domain.update(pkg_cust[CONF_CUSTOMIZE_DOMAIN])
|
||||
cust_glob.update(pkg_cust[CONF_CUSTOMIZE_GLOB])
|
||||
|
||||
hass.data[DATA_CUSTOMIZE] = \
|
||||
EntityValues(cust_exact, cust_domain, cust_glob)
|
||||
|
||||
if CONF_UNIT_SYSTEM in config:
|
||||
if config[CONF_UNIT_SYSTEM] == CONF_UNIT_SYSTEM_IMPERIAL:
|
||||
|
@ -446,20 +475,6 @@ def merge_packages_config(config, packages):
|
|||
return config
|
||||
|
||||
|
||||
def merge_packages_customize(core_customize, packages):
|
||||
"""Merge customize from packages."""
|
||||
schema = vol.Schema({
|
||||
vol.Optional(CONF_CORE): vol.Schema({
|
||||
CONF_CUSTOMIZE: customize.CUSTOMIZE_SCHEMA}),
|
||||
}, extra=vol.ALLOW_EXTRA)
|
||||
|
||||
cust = list(core_customize)
|
||||
for pkg in packages.values():
|
||||
conf = schema(pkg)
|
||||
cust.extend(conf.get(CONF_CORE, {}).get(CONF_CUSTOMIZE, []))
|
||||
return cust
|
||||
|
||||
|
||||
@asyncio.coroutine
|
||||
def async_check_ha_config_file(hass):
|
||||
"""Check if HA config file valid.
|
||||
|
|
|
@ -77,6 +77,8 @@ CONF_COMMAND_STOP = 'command_stop'
|
|||
CONF_CONDITION = 'condition'
|
||||
CONF_COVERS = 'covers'
|
||||
CONF_CUSTOMIZE = 'customize'
|
||||
CONF_CUSTOMIZE_DOMAIN = 'customize_domain'
|
||||
CONF_CUSTOMIZE_GLOB = 'customize_glob'
|
||||
CONF_DEVICE = 'device'
|
||||
CONF_DEVICE_CLASS = 'device_class'
|
||||
CONF_DEVICES = 'devices'
|
||||
|
|
|
@ -1,107 +0,0 @@
|
|||
"""A helper module for customization."""
|
||||
import collections
|
||||
from typing import Any, Dict, List
|
||||
import fnmatch
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.const import CONF_ENTITY_ID
|
||||
from homeassistant.core import HomeAssistant, split_entity_id
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
|
||||
_OVERWRITE_KEY_FORMAT = '{}.overwrite'
|
||||
_OVERWRITE_CACHE_KEY_FORMAT = '{}.overwrite_cache'
|
||||
|
||||
_CUSTOMIZE_SCHEMA_ENTRY = vol.Schema({
|
||||
vol.Required(CONF_ENTITY_ID): vol.All(
|
||||
cv.ensure_list_csv, vol.Length(min=1), [vol.Schema(str)], [vol.Lower])
|
||||
}, extra=vol.ALLOW_EXTRA)
|
||||
|
||||
|
||||
def _convert_old_config(inp: Any) -> List:
|
||||
if not isinstance(inp, dict):
|
||||
return cv.ensure_list(inp)
|
||||
if CONF_ENTITY_ID in inp:
|
||||
return [inp] # sigle entry
|
||||
res = []
|
||||
|
||||
inp = vol.Schema({cv.match_all: dict})(inp)
|
||||
for key, val in inp.items():
|
||||
val = dict(val)
|
||||
val[CONF_ENTITY_ID] = key
|
||||
res.append(val)
|
||||
return res
|
||||
|
||||
|
||||
CUSTOMIZE_SCHEMA = vol.All(_convert_old_config, [_CUSTOMIZE_SCHEMA_ENTRY])
|
||||
|
||||
|
||||
def set_customize(
|
||||
hass: HomeAssistant, domain: str, customize: List[Dict]) -> None:
|
||||
"""Overwrite all current customize settings.
|
||||
|
||||
Async friendly.
|
||||
"""
|
||||
hass.data[_OVERWRITE_KEY_FORMAT.format(domain)] = customize
|
||||
hass.data[_OVERWRITE_CACHE_KEY_FORMAT.format(domain)] = {}
|
||||
|
||||
|
||||
def get_overrides(hass: HomeAssistant, domain: str, entity_id: str) -> Dict:
|
||||
"""Return a dictionary of overrides related to entity_id.
|
||||
|
||||
Whole-domain overrides are of lowest priorities,
|
||||
then glob on entity ID, and finally exact entity_id
|
||||
matches are of highest priority.
|
||||
|
||||
The lookups are cached.
|
||||
"""
|
||||
cache_key = _OVERWRITE_CACHE_KEY_FORMAT.format(domain)
|
||||
if cache_key in hass.data and entity_id in hass.data[cache_key]:
|
||||
return hass.data[cache_key][entity_id]
|
||||
overwrite_key = _OVERWRITE_KEY_FORMAT.format(domain)
|
||||
if overwrite_key not in hass.data:
|
||||
return {}
|
||||
domain_result = {} # type: Dict[str, Any]
|
||||
glob_result = {} # type: Dict[str, Any]
|
||||
exact_result = {} # type: Dict[str, Any]
|
||||
domain = split_entity_id(entity_id)[0]
|
||||
|
||||
def clean_entry(entry: Dict) -> Dict:
|
||||
"""Clean up entity-matching keys."""
|
||||
entry.pop(CONF_ENTITY_ID, None)
|
||||
return entry
|
||||
|
||||
def deep_update(target: Dict, source: Dict) -> None:
|
||||
"""Deep update a dictionary."""
|
||||
for key, value in source.items():
|
||||
if isinstance(value, collections.Mapping):
|
||||
updated_value = target.get(key, {})
|
||||
# If the new value is map, but the old value is not -
|
||||
# overwrite the old value.
|
||||
if not isinstance(updated_value, collections.Mapping):
|
||||
updated_value = {}
|
||||
deep_update(updated_value, value)
|
||||
target[key] = updated_value
|
||||
else:
|
||||
target[key] = source[key]
|
||||
|
||||
for rule in hass.data[overwrite_key]:
|
||||
if CONF_ENTITY_ID in rule:
|
||||
entities = rule[CONF_ENTITY_ID]
|
||||
if domain in entities:
|
||||
deep_update(domain_result, rule)
|
||||
if entity_id in entities:
|
||||
deep_update(exact_result, rule)
|
||||
for entity_id_glob in entities:
|
||||
if entity_id_glob == entity_id:
|
||||
continue
|
||||
if fnmatch.fnmatchcase(entity_id, entity_id_glob):
|
||||
deep_update(glob_result, rule)
|
||||
break
|
||||
result = {}
|
||||
deep_update(result, clean_entry(domain_result))
|
||||
deep_update(result, clean_entry(glob_result))
|
||||
deep_update(result, clean_entry(exact_result))
|
||||
if cache_key not in hass.data:
|
||||
hass.data[cache_key] = {}
|
||||
hass.data[cache_key][entity_id] = result
|
||||
return result
|
|
@ -11,12 +11,12 @@ from homeassistant.const import (
|
|||
ATTR_UNIT_OF_MEASUREMENT, DEVICE_DEFAULT_NAME, STATE_OFF, STATE_ON,
|
||||
STATE_UNAVAILABLE, STATE_UNKNOWN, TEMP_CELSIUS, TEMP_FAHRENHEIT,
|
||||
ATTR_ENTITY_PICTURE, ATTR_SUPPORTED_FEATURES, ATTR_DEVICE_CLASS)
|
||||
from homeassistant.core import HomeAssistant, DOMAIN as CORE_DOMAIN
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.config import DATA_CUSTOMIZE
|
||||
from homeassistant.exceptions import NoEntitySpecifiedError
|
||||
from homeassistant.util import ensure_unique_string, slugify
|
||||
from homeassistant.util.async import (
|
||||
run_coroutine_threadsafe, run_callback_threadsafe)
|
||||
from homeassistant.helpers.customize import get_overrides
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
@ -209,8 +209,6 @@ class Entity(object):
|
|||
# pylint: disable=no-member
|
||||
yield from self.async_update()
|
||||
else:
|
||||
# PS: Run this in our own thread pool once we have
|
||||
# future support?
|
||||
yield from self.hass.loop.run_in_executor(None, self.update)
|
||||
|
||||
start = timer()
|
||||
|
@ -253,7 +251,8 @@ class Entity(object):
|
|||
end - start)
|
||||
|
||||
# Overwrite properties that have been set in the config file.
|
||||
attr.update(get_overrides(self.hass, CORE_DOMAIN, self.entity_id))
|
||||
if DATA_CUSTOMIZE in self.hass.data:
|
||||
attr.update(self.hass.data[DATA_CUSTOMIZE].get(self.entity_id))
|
||||
|
||||
# Remove hidden property if false so it won't show up.
|
||||
if not attr.get(ATTR_HIDDEN, True):
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
"""A class to hold entity values."""
|
||||
from collections import OrderedDict
|
||||
import fnmatch
|
||||
import re
|
||||
|
||||
from homeassistant.core import split_entity_id
|
||||
|
||||
|
||||
class EntityValues(object):
|
||||
"""Class to store entity id based values."""
|
||||
|
||||
def __init__(self, exact=None, domain=None, glob=None):
|
||||
"""Initialize an EntityConfigDict."""
|
||||
self._cache = {}
|
||||
self._exact = exact
|
||||
self._domain = domain
|
||||
|
||||
if glob is None:
|
||||
compiled = None
|
||||
else:
|
||||
compiled = OrderedDict()
|
||||
for key, value in glob.items():
|
||||
compiled[re.compile(fnmatch.translate(key))] = value
|
||||
|
||||
self._glob = compiled
|
||||
|
||||
def get(self, entity_id):
|
||||
"""Get config for an entity id."""
|
||||
if entity_id in self._cache:
|
||||
return self._cache[entity_id]
|
||||
|
||||
domain, _ = split_entity_id(entity_id)
|
||||
result = self._cache[entity_id] = {}
|
||||
|
||||
if self._domain is not None and domain in self._domain:
|
||||
result.update(self._domain[domain])
|
||||
|
||||
if self._glob is not None:
|
||||
for pattern, values in self._glob.items():
|
||||
if pattern.match(entity_id):
|
||||
result.update(values)
|
||||
|
||||
if self._exact is not None and entity_id in self._exact:
|
||||
result.update(self._exact[entity_id])
|
||||
|
||||
return result
|
|
@ -1,119 +0,0 @@
|
|||
"""Test the customize helper."""
|
||||
import homeassistant.helpers.customize as customize
|
||||
from voluptuous import MultipleInvalid
|
||||
import pytest
|
||||
|
||||
|
||||
class MockHass(object):
|
||||
"""Mock object for HassAssistant."""
|
||||
|
||||
data = {}
|
||||
|
||||
|
||||
class TestHelpersCustomize(object):
|
||||
"""Test homeassistant.helpers.customize module."""
|
||||
|
||||
def setup_method(self, method):
|
||||
"""Setup things to be run when tests are started."""
|
||||
self.entity_id = 'test.test'
|
||||
self.hass = MockHass()
|
||||
|
||||
def _get_overrides(self, overrides):
|
||||
test_domain = 'test.domain'
|
||||
customize.set_customize(self.hass, test_domain, overrides)
|
||||
return customize.get_overrides(self.hass, test_domain, self.entity_id)
|
||||
|
||||
def test_override_single_value(self):
|
||||
"""Test entity customization through configuration."""
|
||||
result = self._get_overrides([
|
||||
{'entity_id': [self.entity_id], 'key': 'value'}])
|
||||
|
||||
assert result == {'key': 'value'}
|
||||
|
||||
def test_override_multiple_values(self):
|
||||
"""Test entity customization through configuration."""
|
||||
result = self._get_overrides([
|
||||
{'entity_id': [self.entity_id], 'key1': 'value1'},
|
||||
{'entity_id': [self.entity_id], 'key2': 'value2'}])
|
||||
|
||||
assert result == {'key1': 'value1', 'key2': 'value2'}
|
||||
|
||||
def test_override_same_value(self):
|
||||
"""Test entity customization through configuration."""
|
||||
result = self._get_overrides([
|
||||
{'entity_id': [self.entity_id], 'key': 'value1'},
|
||||
{'entity_id': [self.entity_id], 'key': 'value2'}])
|
||||
|
||||
assert result == {'key': 'value2'}
|
||||
|
||||
def test_override_by_domain(self):
|
||||
"""Test entity customization through configuration."""
|
||||
result = self._get_overrides([
|
||||
{'entity_id': ['test'], 'key': 'value'}])
|
||||
|
||||
assert result == {'key': 'value'}
|
||||
|
||||
def test_override_by_glob(self):
|
||||
"""Test entity customization through configuration."""
|
||||
result = self._get_overrides([
|
||||
{'entity_id': ['test.?e*'], 'key': 'value'}])
|
||||
|
||||
assert result == {'key': 'value'}
|
||||
|
||||
def test_override_exact_over_glob_over_domain(self):
|
||||
"""Test entity customization through configuration."""
|
||||
result = self._get_overrides([
|
||||
{'entity_id': ['test.test'], 'key1': 'valueExact'},
|
||||
{'entity_id': ['test.tes?'],
|
||||
'key1': 'valueGlob',
|
||||
'key2': 'valueGlob'},
|
||||
{'entity_id': ['test'],
|
||||
'key1': 'valueDomain',
|
||||
'key2': 'valueDomain',
|
||||
'key3': 'valueDomain'}])
|
||||
|
||||
assert result == {
|
||||
'key1': 'valueExact',
|
||||
'key2': 'valueGlob',
|
||||
'key3': 'valueDomain'}
|
||||
|
||||
def test_override_deep_dict(self):
|
||||
"""Test we can deep-overwrite a dict."""
|
||||
result = self._get_overrides(
|
||||
[{'entity_id': [self.entity_id],
|
||||
'test': {'key1': 'value1', 'key2': 'value2'}},
|
||||
{'entity_id': [self.entity_id],
|
||||
'test': {'key3': 'value3', 'key2': 'value22'}}])
|
||||
assert result['test'] == {
|
||||
'key1': 'value1',
|
||||
'key2': 'value22',
|
||||
'key3': 'value3'}
|
||||
|
||||
def test_schema_bad_schema(self):
|
||||
"""Test bad customize schemas."""
|
||||
for value in (
|
||||
{'test.test': 10},
|
||||
{'test.test': ['hello']},
|
||||
{'entity_id': {'a': 'b'}},
|
||||
{'entity_id': 10},
|
||||
[{'test.test': 'value'}],
|
||||
):
|
||||
with pytest.raises(
|
||||
MultipleInvalid,
|
||||
message="{} should have raised MultipleInvalid".format(
|
||||
value)):
|
||||
customize.CUSTOMIZE_SCHEMA(value)
|
||||
|
||||
def test_get_customize_schema_allow_extra(self):
|
||||
"""Test schema with ALLOW_EXTRA."""
|
||||
for value in (
|
||||
{'test.test': {'hidden': True}},
|
||||
{'test.test': {'key': ['value1', 'value2']}},
|
||||
[{'entity_id': 'id1', 'key': 'value'}],
|
||||
):
|
||||
customize.CUSTOMIZE_SCHEMA(value)
|
||||
|
||||
def test_get_customize_schema_csv(self):
|
||||
"""Test schema with comma separated entity IDs."""
|
||||
assert [{'entity_id': ['id1', 'id2', 'id3']}] == \
|
||||
customize.CUSTOMIZE_SCHEMA([{'entity_id': 'id1,ID2 , id3'}])
|
|
@ -7,8 +7,9 @@ from unittest.mock import patch
|
|||
import pytest
|
||||
|
||||
import homeassistant.helpers.entity as entity
|
||||
from homeassistant.helpers.customize import set_customize
|
||||
from homeassistant.const import ATTR_HIDDEN, ATTR_DEVICE_CLASS
|
||||
from homeassistant.config import DATA_CUSTOMIZE
|
||||
from homeassistant.helpers.entity_values import EntityValues
|
||||
|
||||
from tests.common import get_test_home_assistant
|
||||
|
||||
|
@ -89,10 +90,8 @@ class TestHelpersEntity(object):
|
|||
|
||||
def test_overwriting_hidden_property_to_true(self):
|
||||
"""Test we can overwrite hidden property to True."""
|
||||
set_customize(
|
||||
self.hass,
|
||||
entity.CORE_DOMAIN,
|
||||
[{'entity_id': [self.entity.entity_id], ATTR_HIDDEN: True}])
|
||||
self.hass.data[DATA_CUSTOMIZE] = EntityValues({
|
||||
self.entity.entity_id: {ATTR_HIDDEN: True}})
|
||||
self.entity.update_ha_state()
|
||||
|
||||
state = self.hass.states.get(self.entity.entity_id)
|
||||
|
|
|
@ -0,0 +1,68 @@
|
|||
"""Test the entity values helper."""
|
||||
from collections import OrderedDict
|
||||
from homeassistant.helpers.entity_values import EntityValues as EV
|
||||
|
||||
ent = 'test.test'
|
||||
|
||||
|
||||
def test_override_single_value():
|
||||
"""Test values with exact match."""
|
||||
store = EV({ent: {'key': 'value'}})
|
||||
assert store.get(ent) == {'key': 'value'}
|
||||
assert len(store._cache) == 1
|
||||
assert store.get(ent) == {'key': 'value'}
|
||||
assert len(store._cache) == 1
|
||||
|
||||
|
||||
def test_override_by_domain():
|
||||
"""Test values with domain match."""
|
||||
store = EV(domain={'test': {'key': 'value'}})
|
||||
assert store.get(ent) == {'key': 'value'}
|
||||
|
||||
|
||||
def test_override_by_glob():
|
||||
"""Test values with glob match."""
|
||||
store = EV(glob={'test.?e*': {'key': 'value'}})
|
||||
assert store.get(ent) == {'key': 'value'}
|
||||
|
||||
|
||||
def test_glob_overrules_domain():
|
||||
"""Test domain overrules glob match."""
|
||||
store = EV(
|
||||
domain={'test': {'key': 'domain'}},
|
||||
glob={'test.?e*': {'key': 'glob'}})
|
||||
assert store.get(ent) == {'key': 'glob'}
|
||||
|
||||
|
||||
def test_exact_overrules_domain():
|
||||
"""Test exact overrules domain match."""
|
||||
store = EV(
|
||||
exact={'test.test': {'key': 'exact'}},
|
||||
domain={'test': {'key': 'domain'}},
|
||||
glob={'test.?e*': {'key': 'glob'}})
|
||||
assert store.get(ent) == {'key': 'exact'}
|
||||
|
||||
|
||||
def test_merging_values():
|
||||
"""Test merging glob, domain and exact configs."""
|
||||
store = EV(
|
||||
exact={'test.test': {'exact_key': 'exact'}},
|
||||
domain={'test': {'domain_key': 'domain'}},
|
||||
glob={'test.?e*': {'glob_key': 'glob'}})
|
||||
assert store.get(ent) == {
|
||||
'exact_key': 'exact',
|
||||
'domain_key': 'domain',
|
||||
'glob_key': 'glob',
|
||||
}
|
||||
|
||||
|
||||
def test_glob_order():
|
||||
"""Test merging glob, domain and exact configs."""
|
||||
glob = OrderedDict()
|
||||
glob['test.*est'] = {"value": "first"}
|
||||
glob['test.*'] = {"value": "second"}
|
||||
|
||||
store = EV(glob=glob)
|
||||
assert store.get(ent) == {
|
||||
'value': 'second'
|
||||
}
|
|
@ -547,11 +547,5 @@ def test_merge_customize(hass):
|
|||
}
|
||||
yield from config_util.async_process_ha_core_config(hass, core_config)
|
||||
|
||||
entity = Entity()
|
||||
entity.entity_id = 'b.b'
|
||||
entity.hass = hass
|
||||
yield from entity.async_update_ha_state()
|
||||
|
||||
state = hass.states.get('b.b')
|
||||
assert state is not None
|
||||
assert state.attributes['friendly_name'] == 'BB'
|
||||
assert hass.data[config_util.DATA_CUSTOMIZE].get('b.b') == \
|
||||
{'friendly_name': 'BB'}
|
||||
|
|
Loading…
Reference in New Issue