mirror of
https://github.com/home-assistant/core.git
synced 2025-07-17 02:07:09 +00:00
Bug fixes related to entity_ids being lowercase
This commit is contained in:
parent
f5084a5f70
commit
ce39a6fb18
@ -51,6 +51,11 @@ def expand_entity_ids(hass, entity_ids):
|
|||||||
found_ids = []
|
found_ids = []
|
||||||
|
|
||||||
for entity_id in entity_ids:
|
for entity_id in entity_ids:
|
||||||
|
if not isinstance(entity_id, str):
|
||||||
|
continue
|
||||||
|
|
||||||
|
entity_id = entity_id.lower()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# If entity_id points at a group, expand it
|
# If entity_id points at a group, expand it
|
||||||
domain, _ = util.split_entity_id(entity_id)
|
domain, _ = util.split_entity_id(entity_id)
|
||||||
@ -74,10 +79,14 @@ def expand_entity_ids(hass, entity_ids):
|
|||||||
|
|
||||||
def get_entity_ids(hass, entity_id, domain_filter=None):
|
def get_entity_ids(hass, entity_id, domain_filter=None):
|
||||||
""" Get the entity ids that make up this group. """
|
""" Get the entity ids that make up this group. """
|
||||||
|
entity_id = entity_id.lower()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
entity_ids = hass.states.get(entity_id).attributes[ATTR_ENTITY_ID]
|
entity_ids = hass.states.get(entity_id).attributes[ATTR_ENTITY_ID]
|
||||||
|
|
||||||
if domain_filter:
|
if domain_filter:
|
||||||
|
domain_filter = domain_filter.lower()
|
||||||
|
|
||||||
return [ent_id for ent_id in entity_ids
|
return [ent_id for ent_id in entity_ids
|
||||||
if ent_id.startswith(domain_filter)]
|
if ent_id.startswith(domain_filter)]
|
||||||
else:
|
else:
|
||||||
@ -131,7 +140,7 @@ class Group(object):
|
|||||||
def update_tracked_entity_ids(self, entity_ids):
|
def update_tracked_entity_ids(self, entity_ids):
|
||||||
""" Update the tracked entity IDs. """
|
""" Update the tracked entity IDs. """
|
||||||
self.stop()
|
self.stop()
|
||||||
self.tracking = tuple(entity_ids)
|
self.tracking = tuple(ent_id.lower() for ent_id in entity_ids)
|
||||||
self.group_on, self.group_off = None, None
|
self.group_on, self.group_off = None, None
|
||||||
|
|
||||||
self.force_update()
|
self.force_update()
|
||||||
|
@ -29,24 +29,18 @@ def extract_entity_ids(hass, service):
|
|||||||
Helper method to extract a list of entity ids from a service call.
|
Helper method to extract a list of entity ids from a service call.
|
||||||
Will convert group entity ids to the entity ids it represents.
|
Will convert group entity ids to the entity ids it represents.
|
||||||
"""
|
"""
|
||||||
entity_ids = []
|
if not (service.data and ATTR_ENTITY_ID in service.data):
|
||||||
|
return []
|
||||||
|
|
||||||
if service.data and ATTR_ENTITY_ID in service.data:
|
group = get_component('group')
|
||||||
group = get_component('group')
|
|
||||||
|
|
||||||
# Entity ID attr can be a list or a string
|
# Entity ID attr can be a list or a string
|
||||||
service_ent_id = service.data[ATTR_ENTITY_ID]
|
service_ent_id = service.data[ATTR_ENTITY_ID]
|
||||||
if isinstance(service_ent_id, list):
|
|
||||||
ent_ids = service_ent_id
|
|
||||||
else:
|
|
||||||
ent_ids = [service_ent_id]
|
|
||||||
|
|
||||||
entity_ids.extend(
|
if isinstance(service_ent_id, str):
|
||||||
ent_id for ent_id
|
return group.expand_entity_ids(hass, [service_ent_id.lower()])
|
||||||
in group.expand_entity_ids(hass, ent_ids)
|
|
||||||
if ent_id not in entity_ids)
|
|
||||||
|
|
||||||
return entity_ids
|
return [ent_id for ent_id in group.expand_entity_ids(hass, service_ent_id)]
|
||||||
|
|
||||||
|
|
||||||
# pylint: disable=too-few-public-methods, attribute-defined-outside-init
|
# pylint: disable=too-few-public-methods, attribute-defined-outside-init
|
||||||
|
@ -78,8 +78,13 @@ class MockToggleDevice(ToggleDevice):
|
|||||||
self._state = STATE_OFF
|
self._state = STATE_OFF
|
||||||
|
|
||||||
def last_call(self, method=None):
|
def last_call(self, method=None):
|
||||||
if method is None:
|
if not self.calls:
|
||||||
|
return None
|
||||||
|
elif method is None:
|
||||||
return self.calls[-1]
|
return self.calls[-1]
|
||||||
else:
|
else:
|
||||||
return next(call for call in reversed(self.calls)
|
try:
|
||||||
if call[0] == method)
|
return next(call for call in reversed(self.calls)
|
||||||
|
if call[0] == method)
|
||||||
|
except StopIteration:
|
||||||
|
return None
|
||||||
|
@ -27,14 +27,10 @@ class TestComponentsGroup(unittest.TestCase):
|
|||||||
|
|
||||||
self.hass.states.set('light.Bowl', STATE_ON)
|
self.hass.states.set('light.Bowl', STATE_ON)
|
||||||
self.hass.states.set('light.Ceiling', STATE_OFF)
|
self.hass.states.set('light.Ceiling', STATE_OFF)
|
||||||
self.hass.states.set('switch.AC', STATE_OFF)
|
test_group = group.Group(
|
||||||
group.setup_group(self.hass, 'init_group',
|
self.hass, 'init_group', ['light.Bowl', 'light.Ceiling'], False)
|
||||||
['light.Bowl', 'light.Ceiling'], False)
|
|
||||||
group.setup_group(self.hass, 'mixed_group',
|
|
||||||
['light.Bowl', 'switch.AC'], False)
|
|
||||||
|
|
||||||
self.group_name = group.ENTITY_ID_FORMAT.format('init_group')
|
self.group_entity_id = test_group.entity_id
|
||||||
self.mixed_group_name = group.ENTITY_ID_FORMAT.format('mixed_group')
|
|
||||||
|
|
||||||
def tearDown(self): # pylint: disable=invalid-name
|
def tearDown(self): # pylint: disable=invalid-name
|
||||||
""" Stop down stuff we started. """
|
""" Stop down stuff we started. """
|
||||||
@ -80,70 +76,94 @@ class TestComponentsGroup(unittest.TestCase):
|
|||||||
""" Test if the group keeps track of states. """
|
""" Test if the group keeps track of states. """
|
||||||
|
|
||||||
# Test if group setup in our init mode is ok
|
# Test if group setup in our init mode is ok
|
||||||
self.assertIn(self.group_name, self.hass.states.entity_ids())
|
self.assertIn(self.group_entity_id, self.hass.states.entity_ids())
|
||||||
|
|
||||||
group_state = self.hass.states.get(self.group_name)
|
group_state = self.hass.states.get(self.group_entity_id)
|
||||||
self.assertEqual(STATE_ON, group_state.state)
|
self.assertEqual(STATE_ON, group_state.state)
|
||||||
self.assertTrue(group_state.attributes[group.ATTR_AUTO])
|
self.assertTrue(group_state.attributes[group.ATTR_AUTO])
|
||||||
|
|
||||||
# Turn the Bowl off and see if group turns off
|
def test_group_turns_off_if_all_off(self):
|
||||||
|
"""
|
||||||
|
Test if the group turns off if the last device that was on turns off.
|
||||||
|
"""
|
||||||
self.hass.states.set('light.Bowl', STATE_OFF)
|
self.hass.states.set('light.Bowl', STATE_OFF)
|
||||||
|
|
||||||
self.hass.pool.block_till_done()
|
self.hass.pool.block_till_done()
|
||||||
|
|
||||||
group_state = self.hass.states.get(self.group_name)
|
group_state = self.hass.states.get(self.group_entity_id)
|
||||||
self.assertEqual(STATE_OFF, group_state.state)
|
self.assertEqual(STATE_OFF, group_state.state)
|
||||||
|
|
||||||
# Turn the Ceiling on and see if group turns on
|
def test_group_turns_on_if_all_are_off_and_one_turns_on(self):
|
||||||
self.hass.states.set('light.Ceiling', STATE_ON)
|
"""
|
||||||
|
Test if group turns on if all devices were turned off and one turns on.
|
||||||
|
"""
|
||||||
|
# Make sure all are off.
|
||||||
|
self.hass.states.set('light.Bowl', STATE_OFF)
|
||||||
self.hass.pool.block_till_done()
|
self.hass.pool.block_till_done()
|
||||||
|
|
||||||
group_state = self.hass.states.get(self.group_name)
|
# Turn one on
|
||||||
|
self.hass.states.set('light.Ceiling', STATE_ON)
|
||||||
|
self.hass.pool.block_till_done()
|
||||||
|
|
||||||
|
group_state = self.hass.states.get(self.group_entity_id)
|
||||||
self.assertEqual(STATE_ON, group_state.state)
|
self.assertEqual(STATE_ON, group_state.state)
|
||||||
|
|
||||||
def test_is_on(self):
|
def test_is_on(self):
|
||||||
""" Test is_on method. """
|
""" Test is_on method. """
|
||||||
self.assertTrue(group.is_on(self.hass, self.group_name))
|
self.assertTrue(group.is_on(self.hass, self.group_entity_id))
|
||||||
self.hass.states.set('light.Bowl', STATE_OFF)
|
self.hass.states.set('light.Bowl', STATE_OFF)
|
||||||
self.hass.pool.block_till_done()
|
self.hass.pool.block_till_done()
|
||||||
self.assertFalse(group.is_on(self.hass, self.group_name))
|
self.assertFalse(group.is_on(self.hass, self.group_entity_id))
|
||||||
|
|
||||||
# Try on non existing state
|
# Try on non existing state
|
||||||
self.assertFalse(group.is_on(self.hass, 'non.existing'))
|
self.assertFalse(group.is_on(self.hass, 'non.existing'))
|
||||||
|
|
||||||
def test_expand_entity_ids(self):
|
def test_expand_entity_ids(self):
|
||||||
""" Test expand_entity_ids method. """
|
""" Test expand_entity_ids method. """
|
||||||
self.assertEqual(sorted(['light.Ceiling', 'light.Bowl']),
|
self.assertEqual(sorted(['light.ceiling', 'light.bowl']),
|
||||||
sorted(group.expand_entity_ids(
|
sorted(group.expand_entity_ids(
|
||||||
self.hass, [self.group_name])))
|
self.hass, [self.group_entity_id])))
|
||||||
|
|
||||||
# Make sure that no duplicates are returned
|
def test_expand_entity_ids_does_not_return_duplicates(self):
|
||||||
|
""" Test that expand_entity_ids does not return duplicates. """
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
sorted(['light.Ceiling', 'light.Bowl']),
|
['light.bowl', 'light.ceiling'],
|
||||||
sorted(group.expand_entity_ids(
|
sorted(group.expand_entity_ids(
|
||||||
self.hass, [self.group_name, 'light.Ceiling'])))
|
self.hass, [self.group_entity_id, 'light.Ceiling'])))
|
||||||
|
|
||||||
# Test that non strings are ignored
|
self.assertEqual(
|
||||||
|
['light.bowl', 'light.ceiling'],
|
||||||
|
sorted(group.expand_entity_ids(
|
||||||
|
self.hass, ['light.bowl', self.group_entity_id])))
|
||||||
|
|
||||||
|
def test_expand_entity_ids_ignores_non_strings(self):
|
||||||
|
""" Test that non string elements in lists are ignored. """
|
||||||
self.assertEqual([], group.expand_entity_ids(self.hass, [5, True]))
|
self.assertEqual([], group.expand_entity_ids(self.hass, [5, True]))
|
||||||
|
|
||||||
def test_get_entity_ids(self):
|
def test_get_entity_ids(self):
|
||||||
""" Test get_entity_ids method. """
|
""" Test get_entity_ids method. """
|
||||||
# Get entity IDs from our group
|
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
sorted(['light.Ceiling', 'light.Bowl']),
|
['light.bowl', 'light.ceiling'],
|
||||||
sorted(group.get_entity_ids(self.hass, self.group_name)))
|
sorted(group.get_entity_ids(self.hass, self.group_entity_id)))
|
||||||
|
|
||||||
|
def test_get_entity_ids_with_domain_filter(self):
|
||||||
|
""" Test if get_entity_ids works with a domain_filter. """
|
||||||
|
self.hass.states.set('switch.AC', STATE_OFF)
|
||||||
|
|
||||||
|
mixed_group = group.Group(
|
||||||
|
self.hass, 'mixed_group', ['light.Bowl', 'switch.AC'], False)
|
||||||
|
|
||||||
# Test domain_filter
|
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
['switch.AC'],
|
['switch.ac'],
|
||||||
group.get_entity_ids(
|
group.get_entity_ids(
|
||||||
self.hass, self.mixed_group_name, domain_filter="switch"))
|
self.hass, mixed_group.entity_id, domain_filter="switch"))
|
||||||
|
|
||||||
# Test with non existing group name
|
def test_get_entity_ids_with_non_existing_group_name(self):
|
||||||
|
""" Tests get_entity_ids with a non existing group. """
|
||||||
self.assertEqual([], group.get_entity_ids(self.hass, 'non_existing'))
|
self.assertEqual([], group.get_entity_ids(self.hass, 'non_existing'))
|
||||||
|
|
||||||
# Test with non-group state
|
def test_get_entity_ids_with_non_group_state(self):
|
||||||
|
""" Tests get_entity_ids with a non group state. """
|
||||||
self.assertEqual([], group.get_entity_ids(self.hass, 'switch.AC'))
|
self.assertEqual([], group.get_entity_ids(self.hass, 'switch.AC'))
|
||||||
|
|
||||||
def test_group_being_init_before_first_tracked_state_is_set_to_on(self):
|
def test_group_being_init_before_first_tracked_state_is_set_to_on(self):
|
||||||
@ -179,7 +199,8 @@ class TestComponentsGroup(unittest.TestCase):
|
|||||||
self.hass,
|
self.hass,
|
||||||
{
|
{
|
||||||
group.DOMAIN: {
|
group.DOMAIN: {
|
||||||
'second_group': '{},light.Bowl'.format(self.group_name)
|
'second_group': ','.join((self.group_entity_id,
|
||||||
|
'light.Bowl'))
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
@ -39,11 +39,11 @@ class TestComponentsCore(unittest.TestCase):
|
|||||||
call = ha.ServiceCall('light', 'turn_on',
|
call = ha.ServiceCall('light', 'turn_on',
|
||||||
{ATTR_ENTITY_ID: 'light.Bowl'})
|
{ATTR_ENTITY_ID: 'light.Bowl'})
|
||||||
|
|
||||||
self.assertEqual(['light.Bowl'],
|
self.assertEqual(['light.bowl'],
|
||||||
extract_entity_ids(self.hass, call))
|
extract_entity_ids(self.hass, call))
|
||||||
|
|
||||||
call = ha.ServiceCall('light', 'turn_on',
|
call = ha.ServiceCall('light', 'turn_on',
|
||||||
{ATTR_ENTITY_ID: 'group.test'})
|
{ATTR_ENTITY_ID: 'group.test'})
|
||||||
|
|
||||||
self.assertEqual(['light.Ceiling', 'light.Kitchen'],
|
self.assertEqual(['light.ceiling', 'light.kitchen'],
|
||||||
extract_entity_ids(self.hass, call))
|
extract_entity_ids(self.hass, call))
|
||||||
|
Loading…
x
Reference in New Issue
Block a user