Implement source switching for homekit_controller televisions (#32526)
This commit is contained in:
parent
0d667c1bd9
commit
2879081772
10 changed files with 177 additions and 16 deletions
|
@ -95,6 +95,16 @@ class HomeKitEntity(Entity):
|
||||||
continue
|
continue
|
||||||
self._setup_characteristic(char)
|
self._setup_characteristic(char)
|
||||||
|
|
||||||
|
accessory = self._accessory.entity_map.aid(self._aid)
|
||||||
|
this_service = accessory.services.iid(self._iid)
|
||||||
|
for child_service in accessory.services.filter(
|
||||||
|
parent_service=this_service
|
||||||
|
):
|
||||||
|
for char in child_service.characteristics:
|
||||||
|
if char.type not in characteristic_types:
|
||||||
|
continue
|
||||||
|
self._setup_characteristic(char.to_accessory_and_service_list())
|
||||||
|
|
||||||
def _setup_characteristic(self, char):
|
def _setup_characteristic(self, char):
|
||||||
"""Configure an entity based on a HomeKit characteristics metadata."""
|
"""Configure an entity based on a HomeKit characteristics metadata."""
|
||||||
# Build up a list of (aid, iid) tuples to poll on update()
|
# Build up a list of (aid, iid) tuples to poll on update()
|
||||||
|
|
|
@ -8,6 +8,7 @@ from aiohomekit.exceptions import (
|
||||||
AccessoryNotFoundError,
|
AccessoryNotFoundError,
|
||||||
EncryptionError,
|
EncryptionError,
|
||||||
)
|
)
|
||||||
|
from aiohomekit.model import Accessories
|
||||||
from aiohomekit.model.characteristics import CharacteristicsTypes
|
from aiohomekit.model.characteristics import CharacteristicsTypes
|
||||||
from aiohomekit.model.services import ServicesTypes
|
from aiohomekit.model.services import ServicesTypes
|
||||||
|
|
||||||
|
@ -69,9 +70,11 @@ class HKDevice:
|
||||||
self.pairing_data["AccessoryPairingID"], self.pairing_data
|
self.pairing_data["AccessoryPairingID"], self.pairing_data
|
||||||
)
|
)
|
||||||
|
|
||||||
self.accessories = {}
|
self.accessories = None
|
||||||
self.config_num = 0
|
self.config_num = 0
|
||||||
|
|
||||||
|
self.entity_map = Accessories()
|
||||||
|
|
||||||
# A list of callbacks that turn HK service metadata into entities
|
# A list of callbacks that turn HK service metadata into entities
|
||||||
self.listeners = []
|
self.listeners = []
|
||||||
|
|
||||||
|
@ -153,6 +156,8 @@ class HKDevice:
|
||||||
self.accessories = cache["accessories"]
|
self.accessories = cache["accessories"]
|
||||||
self.config_num = cache["config_num"]
|
self.config_num = cache["config_num"]
|
||||||
|
|
||||||
|
self.entity_map = Accessories.from_list(self.accessories)
|
||||||
|
|
||||||
self._polling_interval_remover = async_track_time_interval(
|
self._polling_interval_remover = async_track_time_interval(
|
||||||
self.hass, self.async_update, DEFAULT_SCAN_INTERVAL
|
self.hass, self.async_update, DEFAULT_SCAN_INTERVAL
|
||||||
)
|
)
|
||||||
|
@ -213,6 +218,8 @@ class HKDevice:
|
||||||
# later when Bonjour spots c# is still not up to date.
|
# later when Bonjour spots c# is still not up to date.
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
self.entity_map = Accessories.from_list(self.accessories)
|
||||||
|
|
||||||
self.hass.data[ENTITY_MAP].async_create_or_update_map(
|
self.hass.data[ENTITY_MAP].async_create_or_update_map(
|
||||||
self.unique_id, config_num, self.accessories
|
self.unique_id, config_num, self.accessories
|
||||||
)
|
)
|
||||||
|
@ -318,6 +325,10 @@ class HKDevice:
|
||||||
accessory = self.current_state.setdefault(aid, {})
|
accessory = self.current_state.setdefault(aid, {})
|
||||||
accessory[cid] = value
|
accessory[cid] = value
|
||||||
|
|
||||||
|
# self.current_state will be replaced by entity_map in a future PR
|
||||||
|
# For now we update both
|
||||||
|
self.entity_map.process_changes(new_values_dict)
|
||||||
|
|
||||||
self.hass.helpers.dispatcher.async_dispatcher_send(self.signal_state_updated)
|
self.hass.helpers.dispatcher.async_dispatcher_send(self.signal_state_updated)
|
||||||
|
|
||||||
async def get_characteristics(self, *args, **kwargs):
|
async def get_characteristics(self, *args, **kwargs):
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
"name": "HomeKit Controller",
|
"name": "HomeKit Controller",
|
||||||
"config_flow": true,
|
"config_flow": true,
|
||||||
"documentation": "https://www.home-assistant.io/integrations/homekit_controller",
|
"documentation": "https://www.home-assistant.io/integrations/homekit_controller",
|
||||||
"requirements": ["aiohomekit[IP]==0.2.17"],
|
"requirements": ["aiohomekit[IP]==0.2.21"],
|
||||||
"dependencies": [],
|
"dependencies": [],
|
||||||
"zeroconf": ["_hap._tcp.local."],
|
"zeroconf": ["_hap._tcp.local."],
|
||||||
"codeowners": ["@Jc2k"]
|
"codeowners": ["@Jc2k"]
|
||||||
|
|
|
@ -7,12 +7,14 @@ from aiohomekit.model.characteristics import (
|
||||||
RemoteKeyValues,
|
RemoteKeyValues,
|
||||||
TargetMediaStateValues,
|
TargetMediaStateValues,
|
||||||
)
|
)
|
||||||
|
from aiohomekit.model.services import ServicesTypes
|
||||||
from aiohomekit.utils import clamp_enum_to_char
|
from aiohomekit.utils import clamp_enum_to_char
|
||||||
|
|
||||||
from homeassistant.components.media_player import DEVICE_CLASS_TV, MediaPlayerDevice
|
from homeassistant.components.media_player import DEVICE_CLASS_TV, MediaPlayerDevice
|
||||||
from homeassistant.components.media_player.const import (
|
from homeassistant.components.media_player.const import (
|
||||||
SUPPORT_PAUSE,
|
SUPPORT_PAUSE,
|
||||||
SUPPORT_PLAY,
|
SUPPORT_PLAY,
|
||||||
|
SUPPORT_SELECT_SOURCE,
|
||||||
SUPPORT_STOP,
|
SUPPORT_STOP,
|
||||||
)
|
)
|
||||||
from homeassistant.const import STATE_IDLE, STATE_PAUSED, STATE_PLAYING
|
from homeassistant.const import STATE_IDLE, STATE_PAUSED, STATE_PLAYING
|
||||||
|
@ -63,8 +65,15 @@ class HomeKitTelevision(HomeKitEntity, MediaPlayerDevice):
|
||||||
CharacteristicsTypes.CURRENT_MEDIA_STATE,
|
CharacteristicsTypes.CURRENT_MEDIA_STATE,
|
||||||
CharacteristicsTypes.TARGET_MEDIA_STATE,
|
CharacteristicsTypes.TARGET_MEDIA_STATE,
|
||||||
CharacteristicsTypes.REMOTE_KEY,
|
CharacteristicsTypes.REMOTE_KEY,
|
||||||
|
CharacteristicsTypes.ACTIVE_IDENTIFIER,
|
||||||
|
# Characterics that are on the linked INPUT_SOURCE services
|
||||||
|
CharacteristicsTypes.CONFIGURED_NAME,
|
||||||
|
CharacteristicsTypes.IDENTIFIER,
|
||||||
]
|
]
|
||||||
|
|
||||||
|
def _setup_active_identifier(self, char):
|
||||||
|
self._features |= SUPPORT_SELECT_SOURCE
|
||||||
|
|
||||||
def _setup_target_media_state(self, char):
|
def _setup_target_media_state(self, char):
|
||||||
self._supported_target_media_state = clamp_enum_to_char(
|
self._supported_target_media_state = clamp_enum_to_char(
|
||||||
TargetMediaStateValues, char
|
TargetMediaStateValues, char
|
||||||
|
@ -94,6 +103,43 @@ class HomeKitTelevision(HomeKitEntity, MediaPlayerDevice):
|
||||||
"""Flag media player features that are supported."""
|
"""Flag media player features that are supported."""
|
||||||
return self._features
|
return self._features
|
||||||
|
|
||||||
|
@property
|
||||||
|
def source_list(self):
|
||||||
|
"""List of all input sources for this television."""
|
||||||
|
sources = []
|
||||||
|
|
||||||
|
this_accessory = self._accessory.entity_map.aid(self._aid)
|
||||||
|
this_tv = this_accessory.services.iid(self._iid)
|
||||||
|
|
||||||
|
input_sources = this_accessory.services.filter(
|
||||||
|
service_type=ServicesTypes.INPUT_SOURCE, parent_service=this_tv,
|
||||||
|
)
|
||||||
|
|
||||||
|
for input_source in input_sources:
|
||||||
|
char = input_source[CharacteristicsTypes.CONFIGURED_NAME]
|
||||||
|
sources.append(char.value)
|
||||||
|
return sources
|
||||||
|
|
||||||
|
@property
|
||||||
|
def source(self):
|
||||||
|
"""Name of the current input source."""
|
||||||
|
active_identifier = self.get_hk_char_value(
|
||||||
|
CharacteristicsTypes.ACTIVE_IDENTIFIER
|
||||||
|
)
|
||||||
|
if not active_identifier:
|
||||||
|
return None
|
||||||
|
|
||||||
|
this_accessory = self._accessory.entity_map.aid(self._aid)
|
||||||
|
this_tv = this_accessory.services.iid(self._iid)
|
||||||
|
|
||||||
|
input_source = this_accessory.services.first(
|
||||||
|
service_type=ServicesTypes.INPUT_SOURCE,
|
||||||
|
characteristics={CharacteristicsTypes.IDENTIFIER: active_identifier},
|
||||||
|
parent_service=this_tv,
|
||||||
|
)
|
||||||
|
char = input_source[CharacteristicsTypes.CONFIGURED_NAME]
|
||||||
|
return char.value
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def state(self):
|
def state(self):
|
||||||
"""State of the tv."""
|
"""State of the tv."""
|
||||||
|
@ -167,3 +213,28 @@ class HomeKitTelevision(HomeKitEntity, MediaPlayerDevice):
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
await self._accessory.put_characteristics(characteristics)
|
await self._accessory.put_characteristics(characteristics)
|
||||||
|
|
||||||
|
async def async_select_source(self, source):
|
||||||
|
"""Switch to a different media source."""
|
||||||
|
this_accessory = self._accessory.entity_map.aid(self._aid)
|
||||||
|
this_tv = this_accessory.services.iid(self._iid)
|
||||||
|
|
||||||
|
input_source = this_accessory.services.first(
|
||||||
|
service_type=ServicesTypes.INPUT_SOURCE,
|
||||||
|
characteristics={CharacteristicsTypes.CONFIGURED_NAME: source},
|
||||||
|
parent_service=this_tv,
|
||||||
|
)
|
||||||
|
|
||||||
|
if not input_source:
|
||||||
|
raise ValueError(f"Could not find source {source}")
|
||||||
|
|
||||||
|
identifier = input_source[CharacteristicsTypes.IDENTIFIER]
|
||||||
|
|
||||||
|
characteristics = [
|
||||||
|
{
|
||||||
|
"aid": self._aid,
|
||||||
|
"iid": self._chars["active-identifier"],
|
||||||
|
"value": identifier.value,
|
||||||
|
}
|
||||||
|
]
|
||||||
|
await self._accessory.put_characteristics(characteristics)
|
||||||
|
|
|
@ -163,7 +163,7 @@ aioftp==0.12.0
|
||||||
aioharmony==0.1.13
|
aioharmony==0.1.13
|
||||||
|
|
||||||
# homeassistant.components.homekit_controller
|
# homeassistant.components.homekit_controller
|
||||||
aiohomekit[IP]==0.2.17
|
aiohomekit[IP]==0.2.21
|
||||||
|
|
||||||
# homeassistant.components.emulated_hue
|
# homeassistant.components.emulated_hue
|
||||||
# homeassistant.components.http
|
# homeassistant.components.http
|
||||||
|
|
|
@ -62,7 +62,7 @@ aiobotocore==0.11.1
|
||||||
aioesphomeapi==2.6.1
|
aioesphomeapi==2.6.1
|
||||||
|
|
||||||
# homeassistant.components.homekit_controller
|
# homeassistant.components.homekit_controller
|
||||||
aiohomekit[IP]==0.2.17
|
aiohomekit[IP]==0.2.21
|
||||||
|
|
||||||
# homeassistant.components.emulated_hue
|
# homeassistant.components.emulated_hue
|
||||||
# homeassistant.components.http
|
# homeassistant.components.http
|
||||||
|
|
|
@ -67,7 +67,7 @@ async def setup_accessories_from_file(hass, path):
|
||||||
load_fixture, os.path.join("homekit_controller", path)
|
load_fixture, os.path.join("homekit_controller", path)
|
||||||
)
|
)
|
||||||
accessories_json = json.loads(accessories_fixture)
|
accessories_json = json.loads(accessories_fixture)
|
||||||
accessories = Accessory.setup_accessories_from_list(accessories_json)
|
accessories = Accessories.from_list(accessories_json)
|
||||||
return accessories
|
return accessories
|
||||||
|
|
||||||
|
|
||||||
|
@ -153,7 +153,9 @@ async def setup_test_component(hass, setup_accessory, capitalize=False, suffix=N
|
||||||
|
|
||||||
If suffix is set, entityId will include the suffix
|
If suffix is set, entityId will include the suffix
|
||||||
"""
|
"""
|
||||||
accessory = Accessory("TestDevice", "example.com", "Test", "0001", "0.1")
|
accessory = Accessory.create_with_info(
|
||||||
|
"TestDevice", "example.com", "Test", "0001", "0.1"
|
||||||
|
)
|
||||||
setup_accessory(accessory)
|
setup_accessory(accessory)
|
||||||
|
|
||||||
domain = None
|
domain = None
|
||||||
|
|
|
@ -1,7 +1,11 @@
|
||||||
"""Make sure that handling real world LG HomeKit characteristics isn't broken."""
|
"""Make sure that handling real world LG HomeKit characteristics isn't broken."""
|
||||||
|
|
||||||
|
|
||||||
from homeassistant.components.media_player.const import SUPPORT_PAUSE, SUPPORT_PLAY
|
from homeassistant.components.media_player.const import (
|
||||||
|
SUPPORT_PAUSE,
|
||||||
|
SUPPORT_PLAY,
|
||||||
|
SUPPORT_SELECT_SOURCE,
|
||||||
|
)
|
||||||
|
|
||||||
from tests.components.homekit_controller.common import (
|
from tests.components.homekit_controller.common import (
|
||||||
Helper,
|
Helper,
|
||||||
|
@ -29,8 +33,22 @@ async def test_lg_tv(hass):
|
||||||
# Assert that the friendly name is detected correctly
|
# Assert that the friendly name is detected correctly
|
||||||
assert state.attributes["friendly_name"] == "LG webOS TV AF80"
|
assert state.attributes["friendly_name"] == "LG webOS TV AF80"
|
||||||
|
|
||||||
|
# Assert that all channels were found and that we know which is active.
|
||||||
|
assert state.attributes["source_list"] == [
|
||||||
|
"AirPlay",
|
||||||
|
"Live TV",
|
||||||
|
"HDMI 1",
|
||||||
|
"Sony",
|
||||||
|
"Apple",
|
||||||
|
"AV",
|
||||||
|
"HDMI 4",
|
||||||
|
]
|
||||||
|
assert state.attributes["source"] == "HDMI 4"
|
||||||
|
|
||||||
# Assert that all optional features the LS1 supports are detected
|
# Assert that all optional features the LS1 supports are detected
|
||||||
assert state.attributes["supported_features"] == (SUPPORT_PAUSE | SUPPORT_PLAY)
|
assert state.attributes["supported_features"] == (
|
||||||
|
SUPPORT_PAUSE | SUPPORT_PLAY | SUPPORT_SELECT_SOURCE
|
||||||
|
)
|
||||||
|
|
||||||
device_registry = await hass.helpers.device_registry.async_get_registry()
|
device_registry = await hass.helpers.device_registry.async_get_registry()
|
||||||
|
|
||||||
|
|
|
@ -147,7 +147,7 @@ def setup_mock_accessory(controller):
|
||||||
"""Add a bridge accessory to a test controller."""
|
"""Add a bridge accessory to a test controller."""
|
||||||
bridge = Accessories()
|
bridge = Accessories()
|
||||||
|
|
||||||
accessory = Accessory(
|
accessory = Accessory.create_with_info(
|
||||||
name="Koogeek-LS1-20833F",
|
name="Koogeek-LS1-20833F",
|
||||||
manufacturer="Koogeek",
|
manufacturer="Koogeek",
|
||||||
model="LS1",
|
model="LS1",
|
||||||
|
@ -500,7 +500,9 @@ async def test_user_no_unpaired_devices(hass, controller):
|
||||||
|
|
||||||
async def test_parse_new_homekit_json(hass):
|
async def test_parse_new_homekit_json(hass):
|
||||||
"""Test migrating recent .homekit/pairings.json files."""
|
"""Test migrating recent .homekit/pairings.json files."""
|
||||||
accessory = Accessory("TestDevice", "example.com", "Test", "0001", "0.1")
|
accessory = Accessory.create_with_info(
|
||||||
|
"TestDevice", "example.com", "Test", "0001", "0.1"
|
||||||
|
)
|
||||||
service = accessory.add_service(ServicesTypes.LIGHTBULB)
|
service = accessory.add_service(ServicesTypes.LIGHTBULB)
|
||||||
on_char = service.add_char(CharacteristicsTypes.ON)
|
on_char = service.add_char(CharacteristicsTypes.ON)
|
||||||
on_char.value = 0
|
on_char.value = 0
|
||||||
|
@ -549,7 +551,9 @@ async def test_parse_new_homekit_json(hass):
|
||||||
|
|
||||||
async def test_parse_old_homekit_json(hass):
|
async def test_parse_old_homekit_json(hass):
|
||||||
"""Test migrating original .homekit/hk-00:00:00:00:00:00 files."""
|
"""Test migrating original .homekit/hk-00:00:00:00:00:00 files."""
|
||||||
accessory = Accessory("TestDevice", "example.com", "Test", "0001", "0.1")
|
accessory = Accessory.create_with_info(
|
||||||
|
"TestDevice", "example.com", "Test", "0001", "0.1"
|
||||||
|
)
|
||||||
service = accessory.add_service(ServicesTypes.LIGHTBULB)
|
service = accessory.add_service(ServicesTypes.LIGHTBULB)
|
||||||
on_char = service.add_char(CharacteristicsTypes.ON)
|
on_char = service.add_char(CharacteristicsTypes.ON)
|
||||||
on_char.value = 0
|
on_char.value = 0
|
||||||
|
@ -602,7 +606,9 @@ async def test_parse_old_homekit_json(hass):
|
||||||
|
|
||||||
async def test_parse_overlapping_homekit_json(hass):
|
async def test_parse_overlapping_homekit_json(hass):
|
||||||
"""Test migrating .homekit/pairings.json files when hk- exists too."""
|
"""Test migrating .homekit/pairings.json files when hk- exists too."""
|
||||||
accessory = Accessory("TestDevice", "example.com", "Test", "0001", "0.1")
|
accessory = Accessory.create_with_info(
|
||||||
|
"TestDevice", "example.com", "Test", "0001", "0.1"
|
||||||
|
)
|
||||||
service = accessory.add_service(ServicesTypes.LIGHTBULB)
|
service = accessory.add_service(ServicesTypes.LIGHTBULB)
|
||||||
on_char = service.add_char(CharacteristicsTypes.ON)
|
on_char = service.add_char(CharacteristicsTypes.ON)
|
||||||
on_char.value = 0
|
on_char.value = 0
|
||||||
|
|
|
@ -10,6 +10,7 @@ from tests.components.homekit_controller.common import setup_test_component
|
||||||
CURRENT_MEDIA_STATE = ("television", "current-media-state")
|
CURRENT_MEDIA_STATE = ("television", "current-media-state")
|
||||||
TARGET_MEDIA_STATE = ("television", "target-media-state")
|
TARGET_MEDIA_STATE = ("television", "target-media-state")
|
||||||
REMOTE_KEY = ("television", "remote-key")
|
REMOTE_KEY = ("television", "remote-key")
|
||||||
|
ACTIVE_IDENTIFIER = ("television", "active-identifier")
|
||||||
|
|
||||||
|
|
||||||
def create_tv_service(accessory):
|
def create_tv_service(accessory):
|
||||||
|
@ -18,16 +19,33 @@ def create_tv_service(accessory):
|
||||||
|
|
||||||
The TV is not currently documented publicly - this is based on observing really TV's that have HomeKit support.
|
The TV is not currently documented publicly - this is based on observing really TV's that have HomeKit support.
|
||||||
"""
|
"""
|
||||||
service = accessory.add_service(ServicesTypes.TELEVISION)
|
tv_service = accessory.add_service(ServicesTypes.TELEVISION)
|
||||||
|
|
||||||
cur_state = service.add_char(CharacteristicsTypes.CURRENT_MEDIA_STATE)
|
cur_state = tv_service.add_char(CharacteristicsTypes.CURRENT_MEDIA_STATE)
|
||||||
cur_state.value = 0
|
cur_state.value = 0
|
||||||
|
|
||||||
remote = service.add_char(CharacteristicsTypes.REMOTE_KEY)
|
remote = tv_service.add_char(CharacteristicsTypes.REMOTE_KEY)
|
||||||
remote.value = None
|
remote.value = None
|
||||||
remote.perms.append(CharacteristicPermissions.paired_write)
|
remote.perms.append(CharacteristicPermissions.paired_write)
|
||||||
|
|
||||||
return service
|
# Add a HDMI 1 channel
|
||||||
|
input_source_1 = accessory.add_service(ServicesTypes.INPUT_SOURCE)
|
||||||
|
input_source_1.add_char(CharacteristicsTypes.IDENTIFIER, value=1)
|
||||||
|
input_source_1.add_char(CharacteristicsTypes.CONFIGURED_NAME, value="HDMI 1")
|
||||||
|
tv_service.add_linked_service(input_source_1)
|
||||||
|
|
||||||
|
# Add a HDMI 2 channel
|
||||||
|
input_source_2 = accessory.add_service(ServicesTypes.INPUT_SOURCE)
|
||||||
|
input_source_2.add_char(CharacteristicsTypes.IDENTIFIER, value=2)
|
||||||
|
input_source_2.add_char(CharacteristicsTypes.CONFIGURED_NAME, value="HDMI 2")
|
||||||
|
tv_service.add_linked_service(input_source_2)
|
||||||
|
|
||||||
|
# Support switching channels
|
||||||
|
active_identifier = tv_service.add_char(CharacteristicsTypes.ACTIVE_IDENTIFIER)
|
||||||
|
active_identifier.value = 1
|
||||||
|
active_identifier.perms.append(CharacteristicPermissions.paired_write)
|
||||||
|
|
||||||
|
return tv_service
|
||||||
|
|
||||||
|
|
||||||
def create_tv_service_with_target_media_state(accessory):
|
def create_tv_service_with_target_media_state(accessory):
|
||||||
|
@ -58,6 +76,15 @@ async def test_tv_read_state(hass, utcnow):
|
||||||
assert state.state == "idle"
|
assert state.state == "idle"
|
||||||
|
|
||||||
|
|
||||||
|
async def test_tv_read_sources(hass, utcnow):
|
||||||
|
"""Test that we can read the input source of a HomeKit TV."""
|
||||||
|
helper = await setup_test_component(hass, create_tv_service)
|
||||||
|
|
||||||
|
state = await helper.poll_and_get_state()
|
||||||
|
assert state.attributes["source"] == "HDMI 1"
|
||||||
|
assert state.attributes["source_list"] == ["HDMI 1", "HDMI 2"]
|
||||||
|
|
||||||
|
|
||||||
async def test_play_remote_key(hass, utcnow):
|
async def test_play_remote_key(hass, utcnow):
|
||||||
"""Test that we can play media on a media player."""
|
"""Test that we can play media on a media player."""
|
||||||
helper = await setup_test_component(hass, create_tv_service)
|
helper = await setup_test_component(hass, create_tv_service)
|
||||||
|
@ -202,3 +229,19 @@ async def test_stop(hass, utcnow):
|
||||||
)
|
)
|
||||||
assert helper.characteristics[REMOTE_KEY].value is None
|
assert helper.characteristics[REMOTE_KEY].value is None
|
||||||
assert helper.characteristics[TARGET_MEDIA_STATE].value is None
|
assert helper.characteristics[TARGET_MEDIA_STATE].value is None
|
||||||
|
|
||||||
|
|
||||||
|
async def test_tv_set_source(hass, utcnow):
|
||||||
|
"""Test that we can set the input source of a HomeKit TV."""
|
||||||
|
helper = await setup_test_component(hass, create_tv_service)
|
||||||
|
|
||||||
|
await hass.services.async_call(
|
||||||
|
"media_player",
|
||||||
|
"select_source",
|
||||||
|
{"entity_id": "media_player.testdevice", "source": "HDMI 2"},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
assert helper.characteristics[ACTIVE_IDENTIFIER].value == 2
|
||||||
|
|
||||||
|
state = await helper.poll_and_get_state()
|
||||||
|
assert state.attributes["source"] == "HDMI 2"
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue