mirror of
https://github.com/home-assistant/core.git
synced 2025-07-25 14:17:45 +00:00
Limit homekit sources to prevent exceeding 100 limit (#59743)
This commit is contained in:
parent
5c443b626a
commit
52e0027fad
@ -52,6 +52,10 @@ from .const import (
|
|||||||
SERV_TELEVISION,
|
SERV_TELEVISION,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
MAXIMUM_SOURCES = (
|
||||||
|
90 # Maximum services per accessory is 100. The base acccessory uses 9
|
||||||
|
)
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
REMOTE_KEYS = {
|
REMOTE_KEYS = {
|
||||||
@ -92,7 +96,14 @@ class RemoteInputSelectAccessory(HomeAccessory):
|
|||||||
self.sources = []
|
self.sources = []
|
||||||
self.support_select_source = False
|
self.support_select_source = False
|
||||||
if features & required_feature:
|
if features & required_feature:
|
||||||
self.sources = state.attributes.get(source_list_key, [])
|
sources = state.attributes.get(source_list_key, [])
|
||||||
|
if len(sources) > MAXIMUM_SOURCES:
|
||||||
|
_LOGGER.warning(
|
||||||
|
"%s: Reached maximum number of sources (%s)",
|
||||||
|
self.entity_id,
|
||||||
|
MAXIMUM_SOURCES,
|
||||||
|
)
|
||||||
|
self.sources = sources[:MAXIMUM_SOURCES]
|
||||||
if self.sources:
|
if self.sources:
|
||||||
self.support_select_source = True
|
self.support_select_source = True
|
||||||
|
|
||||||
@ -159,13 +170,21 @@ class RemoteInputSelectAccessory(HomeAccessory):
|
|||||||
|
|
||||||
possible_sources = new_state.attributes.get(self.source_list_key, [])
|
possible_sources = new_state.attributes.get(self.source_list_key, [])
|
||||||
if source_name in possible_sources:
|
if source_name in possible_sources:
|
||||||
_LOGGER.debug(
|
index = possible_sources.index(source_name)
|
||||||
"%s: Sources out of sync. Rebuilding Accessory",
|
if index >= MAXIMUM_SOURCES:
|
||||||
self.entity_id,
|
_LOGGER.debug(
|
||||||
)
|
"%s: Source %s and above are not supported",
|
||||||
# Sources are out of sync, recreate the accessory
|
self.entity_id,
|
||||||
self.async_reset()
|
MAXIMUM_SOURCES,
|
||||||
return
|
)
|
||||||
|
else:
|
||||||
|
_LOGGER.debug(
|
||||||
|
"%s: Sources out of sync. Rebuilding Accessory",
|
||||||
|
self.entity_id,
|
||||||
|
)
|
||||||
|
# Sources are out of sync, recreate the accessory
|
||||||
|
self.async_reset()
|
||||||
|
return
|
||||||
|
|
||||||
_LOGGER.debug(
|
_LOGGER.debug(
|
||||||
"%s: Source %s does not exist the source list: %s",
|
"%s: Source %s does not exist the source list: %s",
|
||||||
|
@ -112,63 +112,49 @@ async def test_media_player_set_state(hass, hk_driver, events):
|
|||||||
call_media_stop = async_mock_service(hass, DOMAIN, "media_stop")
|
call_media_stop = async_mock_service(hass, DOMAIN, "media_stop")
|
||||||
call_toggle_mute = async_mock_service(hass, DOMAIN, "volume_mute")
|
call_toggle_mute = async_mock_service(hass, DOMAIN, "volume_mute")
|
||||||
|
|
||||||
await hass.async_add_executor_job(
|
acc.chars[FEATURE_ON_OFF].client_update_value(True)
|
||||||
acc.chars[FEATURE_ON_OFF].client_update_value, True
|
|
||||||
)
|
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
assert call_turn_on
|
assert call_turn_on
|
||||||
assert call_turn_on[0].data[ATTR_ENTITY_ID] == entity_id
|
assert call_turn_on[0].data[ATTR_ENTITY_ID] == entity_id
|
||||||
assert len(events) == 1
|
assert len(events) == 1
|
||||||
assert events[-1].data[ATTR_VALUE] is None
|
assert events[-1].data[ATTR_VALUE] is None
|
||||||
|
|
||||||
await hass.async_add_executor_job(
|
acc.chars[FEATURE_ON_OFF].client_update_value(False)
|
||||||
acc.chars[FEATURE_ON_OFF].client_update_value, False
|
|
||||||
)
|
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
assert call_turn_off
|
assert call_turn_off
|
||||||
assert call_turn_off[0].data[ATTR_ENTITY_ID] == entity_id
|
assert call_turn_off[0].data[ATTR_ENTITY_ID] == entity_id
|
||||||
assert len(events) == 2
|
assert len(events) == 2
|
||||||
assert events[-1].data[ATTR_VALUE] is None
|
assert events[-1].data[ATTR_VALUE] is None
|
||||||
|
|
||||||
await hass.async_add_executor_job(
|
acc.chars[FEATURE_PLAY_PAUSE].client_update_value(True)
|
||||||
acc.chars[FEATURE_PLAY_PAUSE].client_update_value, True
|
|
||||||
)
|
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
assert call_media_play
|
assert call_media_play
|
||||||
assert call_media_play[0].data[ATTR_ENTITY_ID] == entity_id
|
assert call_media_play[0].data[ATTR_ENTITY_ID] == entity_id
|
||||||
assert len(events) == 3
|
assert len(events) == 3
|
||||||
assert events[-1].data[ATTR_VALUE] is None
|
assert events[-1].data[ATTR_VALUE] is None
|
||||||
|
|
||||||
await hass.async_add_executor_job(
|
acc.chars[FEATURE_PLAY_PAUSE].client_update_value(False)
|
||||||
acc.chars[FEATURE_PLAY_PAUSE].client_update_value, False
|
|
||||||
)
|
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
assert call_media_pause
|
assert call_media_pause
|
||||||
assert call_media_pause[0].data[ATTR_ENTITY_ID] == entity_id
|
assert call_media_pause[0].data[ATTR_ENTITY_ID] == entity_id
|
||||||
assert len(events) == 4
|
assert len(events) == 4
|
||||||
assert events[-1].data[ATTR_VALUE] is None
|
assert events[-1].data[ATTR_VALUE] is None
|
||||||
|
|
||||||
await hass.async_add_executor_job(
|
acc.chars[FEATURE_PLAY_STOP].client_update_value(True)
|
||||||
acc.chars[FEATURE_PLAY_STOP].client_update_value, True
|
|
||||||
)
|
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
assert call_media_play
|
assert call_media_play
|
||||||
assert call_media_play[1].data[ATTR_ENTITY_ID] == entity_id
|
assert call_media_play[1].data[ATTR_ENTITY_ID] == entity_id
|
||||||
assert len(events) == 5
|
assert len(events) == 5
|
||||||
assert events[-1].data[ATTR_VALUE] is None
|
assert events[-1].data[ATTR_VALUE] is None
|
||||||
|
|
||||||
await hass.async_add_executor_job(
|
acc.chars[FEATURE_PLAY_STOP].client_update_value(False)
|
||||||
acc.chars[FEATURE_PLAY_STOP].client_update_value, False
|
|
||||||
)
|
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
assert call_media_stop
|
assert call_media_stop
|
||||||
assert call_media_stop[0].data[ATTR_ENTITY_ID] == entity_id
|
assert call_media_stop[0].data[ATTR_ENTITY_ID] == entity_id
|
||||||
assert len(events) == 6
|
assert len(events) == 6
|
||||||
assert events[-1].data[ATTR_VALUE] is None
|
assert events[-1].data[ATTR_VALUE] is None
|
||||||
|
|
||||||
await hass.async_add_executor_job(
|
acc.chars[FEATURE_TOGGLE_MUTE].client_update_value(True)
|
||||||
acc.chars[FEATURE_TOGGLE_MUTE].client_update_value, True
|
|
||||||
)
|
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
assert call_toggle_mute
|
assert call_toggle_mute
|
||||||
assert call_toggle_mute[0].data[ATTR_ENTITY_ID] == entity_id
|
assert call_toggle_mute[0].data[ATTR_ENTITY_ID] == entity_id
|
||||||
@ -176,9 +162,7 @@ async def test_media_player_set_state(hass, hk_driver, events):
|
|||||||
assert len(events) == 7
|
assert len(events) == 7
|
||||||
assert events[-1].data[ATTR_VALUE] is None
|
assert events[-1].data[ATTR_VALUE] is None
|
||||||
|
|
||||||
await hass.async_add_executor_job(
|
acc.chars[FEATURE_TOGGLE_MUTE].client_update_value(False)
|
||||||
acc.chars[FEATURE_TOGGLE_MUTE].client_update_value, False
|
|
||||||
)
|
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
assert call_toggle_mute
|
assert call_toggle_mute
|
||||||
assert call_toggle_mute[1].data[ATTR_ENTITY_ID] == entity_id
|
assert call_toggle_mute[1].data[ATTR_ENTITY_ID] == entity_id
|
||||||
@ -258,21 +242,21 @@ async def test_media_player_television(hass, hk_driver, events, caplog):
|
|||||||
call_volume_down = async_mock_service(hass, DOMAIN, "volume_down")
|
call_volume_down = async_mock_service(hass, DOMAIN, "volume_down")
|
||||||
call_volume_set = async_mock_service(hass, DOMAIN, "volume_set")
|
call_volume_set = async_mock_service(hass, DOMAIN, "volume_set")
|
||||||
|
|
||||||
await hass.async_add_executor_job(acc.char_active.client_update_value, 1)
|
acc.char_active.client_update_value(1)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
assert call_turn_on
|
assert call_turn_on
|
||||||
assert call_turn_on[0].data[ATTR_ENTITY_ID] == entity_id
|
assert call_turn_on[0].data[ATTR_ENTITY_ID] == entity_id
|
||||||
assert len(events) == 1
|
assert len(events) == 1
|
||||||
assert events[-1].data[ATTR_VALUE] is None
|
assert events[-1].data[ATTR_VALUE] is None
|
||||||
|
|
||||||
await hass.async_add_executor_job(acc.char_active.client_update_value, 0)
|
acc.char_active.client_update_value(0)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
assert call_turn_off
|
assert call_turn_off
|
||||||
assert call_turn_off[0].data[ATTR_ENTITY_ID] == entity_id
|
assert call_turn_off[0].data[ATTR_ENTITY_ID] == entity_id
|
||||||
assert len(events) == 2
|
assert len(events) == 2
|
||||||
assert events[-1].data[ATTR_VALUE] is None
|
assert events[-1].data[ATTR_VALUE] is None
|
||||||
|
|
||||||
await hass.async_add_executor_job(acc.char_remote_key.client_update_value, 11)
|
acc.char_remote_key.client_update_value(11)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
assert call_media_play_pause
|
assert call_media_play_pause
|
||||||
assert call_media_play_pause[0].data[ATTR_ENTITY_ID] == entity_id
|
assert call_media_play_pause[0].data[ATTR_ENTITY_ID] == entity_id
|
||||||
@ -281,28 +265,28 @@ async def test_media_player_television(hass, hk_driver, events, caplog):
|
|||||||
|
|
||||||
hass.states.async_set(entity_id, STATE_PLAYING)
|
hass.states.async_set(entity_id, STATE_PLAYING)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
await hass.async_add_executor_job(acc.char_remote_key.client_update_value, 11)
|
acc.char_remote_key.client_update_value(11)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
assert call_media_pause
|
assert call_media_pause
|
||||||
assert call_media_pause[0].data[ATTR_ENTITY_ID] == entity_id
|
assert call_media_pause[0].data[ATTR_ENTITY_ID] == entity_id
|
||||||
assert len(events) == 4
|
assert len(events) == 4
|
||||||
assert events[-1].data[ATTR_VALUE] is None
|
assert events[-1].data[ATTR_VALUE] is None
|
||||||
|
|
||||||
await hass.async_add_executor_job(acc.char_remote_key.client_update_value, 10)
|
acc.char_remote_key.client_update_value(10)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
assert len(events) == 4
|
assert len(events) == 4
|
||||||
assert events[-1].data[ATTR_VALUE] is None
|
assert events[-1].data[ATTR_VALUE] is None
|
||||||
|
|
||||||
hass.states.async_set(entity_id, STATE_PAUSED)
|
hass.states.async_set(entity_id, STATE_PAUSED)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
await hass.async_add_executor_job(acc.char_remote_key.client_update_value, 11)
|
acc.char_remote_key.client_update_value(11)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
assert call_media_play
|
assert call_media_play
|
||||||
assert call_media_play[0].data[ATTR_ENTITY_ID] == entity_id
|
assert call_media_play[0].data[ATTR_ENTITY_ID] == entity_id
|
||||||
assert len(events) == 5
|
assert len(events) == 5
|
||||||
assert events[-1].data[ATTR_VALUE] is None
|
assert events[-1].data[ATTR_VALUE] is None
|
||||||
|
|
||||||
await hass.async_add_executor_job(acc.char_mute.client_update_value, True)
|
acc.char_mute.client_update_value(True)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
assert call_toggle_mute
|
assert call_toggle_mute
|
||||||
assert call_toggle_mute[0].data[ATTR_ENTITY_ID] == entity_id
|
assert call_toggle_mute[0].data[ATTR_ENTITY_ID] == entity_id
|
||||||
@ -310,7 +294,7 @@ async def test_media_player_television(hass, hk_driver, events, caplog):
|
|||||||
assert len(events) == 6
|
assert len(events) == 6
|
||||||
assert events[-1].data[ATTR_VALUE] is None
|
assert events[-1].data[ATTR_VALUE] is None
|
||||||
|
|
||||||
await hass.async_add_executor_job(acc.char_mute.client_update_value, False)
|
acc.char_mute.client_update_value(False)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
assert call_toggle_mute
|
assert call_toggle_mute
|
||||||
assert call_toggle_mute[1].data[ATTR_ENTITY_ID] == entity_id
|
assert call_toggle_mute[1].data[ATTR_ENTITY_ID] == entity_id
|
||||||
@ -318,7 +302,7 @@ async def test_media_player_television(hass, hk_driver, events, caplog):
|
|||||||
assert len(events) == 7
|
assert len(events) == 7
|
||||||
assert events[-1].data[ATTR_VALUE] is None
|
assert events[-1].data[ATTR_VALUE] is None
|
||||||
|
|
||||||
await hass.async_add_executor_job(acc.char_input_source.client_update_value, 1)
|
acc.char_input_source.client_update_value(1)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
assert call_select_source
|
assert call_select_source
|
||||||
assert call_select_source[0].data[ATTR_ENTITY_ID] == entity_id
|
assert call_select_source[0].data[ATTR_ENTITY_ID] == entity_id
|
||||||
@ -326,21 +310,21 @@ async def test_media_player_television(hass, hk_driver, events, caplog):
|
|||||||
assert len(events) == 8
|
assert len(events) == 8
|
||||||
assert events[-1].data[ATTR_VALUE] is None
|
assert events[-1].data[ATTR_VALUE] is None
|
||||||
|
|
||||||
await hass.async_add_executor_job(acc.char_volume_selector.client_update_value, 0)
|
acc.char_volume_selector.client_update_value(0)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
assert call_volume_up
|
assert call_volume_up
|
||||||
assert call_volume_up[0].data[ATTR_ENTITY_ID] == entity_id
|
assert call_volume_up[0].data[ATTR_ENTITY_ID] == entity_id
|
||||||
assert len(events) == 9
|
assert len(events) == 9
|
||||||
assert events[-1].data[ATTR_VALUE] is None
|
assert events[-1].data[ATTR_VALUE] is None
|
||||||
|
|
||||||
await hass.async_add_executor_job(acc.char_volume_selector.client_update_value, 1)
|
acc.char_volume_selector.client_update_value(1)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
assert call_volume_down
|
assert call_volume_down
|
||||||
assert call_volume_down[0].data[ATTR_ENTITY_ID] == entity_id
|
assert call_volume_down[0].data[ATTR_ENTITY_ID] == entity_id
|
||||||
assert len(events) == 10
|
assert len(events) == 10
|
||||||
assert events[-1].data[ATTR_VALUE] is None
|
assert events[-1].data[ATTR_VALUE] is None
|
||||||
|
|
||||||
await hass.async_add_executor_job(acc.char_volume.client_update_value, 20)
|
acc.char_volume.client_update_value(20)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
assert call_volume_set[0]
|
assert call_volume_set[0]
|
||||||
assert call_volume_set[0].data[ATTR_ENTITY_ID] == entity_id
|
assert call_volume_set[0].data[ATTR_ENTITY_ID] == entity_id
|
||||||
@ -356,10 +340,10 @@ async def test_media_player_television(hass, hk_driver, events, caplog):
|
|||||||
hass.bus.async_listen(EVENT_HOMEKIT_TV_REMOTE_KEY_PRESSED, listener)
|
hass.bus.async_listen(EVENT_HOMEKIT_TV_REMOTE_KEY_PRESSED, listener)
|
||||||
|
|
||||||
with pytest.raises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
await hass.async_add_executor_job(acc.char_remote_key.client_update_value, 20)
|
acc.char_remote_key.client_update_value(20)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
await hass.async_add_executor_job(acc.char_remote_key.client_update_value, 7)
|
acc.char_remote_key.client_update_value(7)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
assert len(events) == 1
|
assert len(events) == 1
|
||||||
@ -471,3 +455,60 @@ async def test_tv_restore(hass, hk_driver, events):
|
|||||||
]
|
]
|
||||||
assert acc.support_select_source is True
|
assert acc.support_select_source is True
|
||||||
assert acc.char_input_source is not None
|
assert acc.char_input_source is not None
|
||||||
|
|
||||||
|
|
||||||
|
async def test_media_player_television_max_sources(hass, hk_driver, events, caplog):
|
||||||
|
"""Test if television accessory that reaches the maximum number of sources."""
|
||||||
|
entity_id = "media_player.television"
|
||||||
|
sources = [f"HDMI {i}" for i in range(1, 101)]
|
||||||
|
hass.states.async_set(
|
||||||
|
entity_id,
|
||||||
|
None,
|
||||||
|
{
|
||||||
|
ATTR_DEVICE_CLASS: DEVICE_CLASS_TV,
|
||||||
|
ATTR_SUPPORTED_FEATURES: 3469,
|
||||||
|
ATTR_MEDIA_VOLUME_MUTED: False,
|
||||||
|
ATTR_INPUT_SOURCE: "HDMI 3",
|
||||||
|
ATTR_INPUT_SOURCE_LIST: sources,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
acc = TelevisionMediaPlayer(hass, hk_driver, "MediaPlayer", entity_id, 2, None)
|
||||||
|
await acc.run()
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
assert acc.aid == 2
|
||||||
|
assert acc.category == 31 # Television
|
||||||
|
|
||||||
|
assert acc.char_active.value == 0
|
||||||
|
assert acc.char_remote_key.value == 0
|
||||||
|
assert acc.char_input_source.value == 2
|
||||||
|
assert acc.char_mute.value is False
|
||||||
|
|
||||||
|
hass.states.async_set(
|
||||||
|
entity_id,
|
||||||
|
None,
|
||||||
|
{
|
||||||
|
ATTR_DEVICE_CLASS: DEVICE_CLASS_TV,
|
||||||
|
ATTR_SUPPORTED_FEATURES: 3469,
|
||||||
|
ATTR_MEDIA_VOLUME_MUTED: False,
|
||||||
|
ATTR_INPUT_SOURCE: "HDMI 90",
|
||||||
|
ATTR_INPUT_SOURCE_LIST: sources,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
assert acc.char_input_source.value == 89
|
||||||
|
|
||||||
|
hass.states.async_set(
|
||||||
|
entity_id,
|
||||||
|
None,
|
||||||
|
{
|
||||||
|
ATTR_DEVICE_CLASS: DEVICE_CLASS_TV,
|
||||||
|
ATTR_SUPPORTED_FEATURES: 3469,
|
||||||
|
ATTR_MEDIA_VOLUME_MUTED: False,
|
||||||
|
ATTR_INPUT_SOURCE: "HDMI 91",
|
||||||
|
ATTR_INPUT_SOURCE_LIST: sources,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
assert acc.char_input_source.value == 0
|
||||||
|
Loading…
x
Reference in New Issue
Block a user