Add samsungtv dhcp and zeroconf discovery (#48022)
Co-authored-by: J. Nick Koston <nick@koston.org>
This commit is contained in:
@@ -25,6 +25,7 @@ from homeassistant.components.media_player.const import (
|
||||
from homeassistant.components.samsungtv.const import (
|
||||
CONF_ON_ACTION,
|
||||
DOMAIN as SAMSUNGTV_DOMAIN,
|
||||
TIMEOUT_WEBSOCKET,
|
||||
)
|
||||
from homeassistant.components.samsungtv.media_player import SUPPORT_SAMSUNGTV
|
||||
from homeassistant.const import (
|
||||
@@ -37,10 +38,12 @@ from homeassistant.const import (
|
||||
CONF_METHOD,
|
||||
CONF_NAME,
|
||||
CONF_PORT,
|
||||
CONF_TIMEOUT,
|
||||
CONF_TOKEN,
|
||||
SERVICE_MEDIA_NEXT_TRACK,
|
||||
SERVICE_MEDIA_PAUSE,
|
||||
SERVICE_MEDIA_PLAY,
|
||||
SERVICE_MEDIA_PLAY_PAUSE,
|
||||
SERVICE_MEDIA_PREVIOUS_TRACK,
|
||||
SERVICE_TURN_OFF,
|
||||
SERVICE_TURN_ON,
|
||||
@@ -49,6 +52,7 @@ from homeassistant.const import (
|
||||
SERVICE_VOLUME_UP,
|
||||
STATE_OFF,
|
||||
STATE_ON,
|
||||
STATE_UNAVAILABLE,
|
||||
)
|
||||
from homeassistant.setup import async_setup_component
|
||||
import homeassistant.util.dt as dt_util
|
||||
@@ -59,7 +63,7 @@ ENTITY_ID = f"{DOMAIN}.fake"
|
||||
MOCK_CONFIG = {
|
||||
SAMSUNGTV_DOMAIN: [
|
||||
{
|
||||
CONF_HOST: "fake",
|
||||
CONF_HOST: "fake_host",
|
||||
CONF_NAME: "fake",
|
||||
CONF_PORT: 55000,
|
||||
CONF_ON_ACTION: [{"delay": "00:00:01"}],
|
||||
@@ -69,7 +73,7 @@ MOCK_CONFIG = {
|
||||
MOCK_CONFIGWS = {
|
||||
SAMSUNGTV_DOMAIN: [
|
||||
{
|
||||
CONF_HOST: "fake",
|
||||
CONF_HOST: "fake_host",
|
||||
CONF_NAME: "fake",
|
||||
CONF_PORT: 8001,
|
||||
CONF_TOKEN: "123456789",
|
||||
@@ -78,27 +82,20 @@ MOCK_CONFIGWS = {
|
||||
]
|
||||
}
|
||||
MOCK_CALLS_WS = {
|
||||
"host": "fake",
|
||||
"port": 8001,
|
||||
"token": None,
|
||||
"timeout": 31,
|
||||
"name": "HomeAssistant",
|
||||
CONF_HOST: "fake_host",
|
||||
CONF_PORT: 8001,
|
||||
CONF_TOKEN: "123456789",
|
||||
CONF_TIMEOUT: TIMEOUT_WEBSOCKET,
|
||||
CONF_NAME: "HomeAssistant",
|
||||
}
|
||||
|
||||
MOCK_ENTRY_WS = {
|
||||
CONF_IP_ADDRESS: "test",
|
||||
CONF_HOST: "fake",
|
||||
CONF_HOST: "fake_host",
|
||||
CONF_METHOD: "websocket",
|
||||
CONF_NAME: "fake",
|
||||
CONF_PORT: 8001,
|
||||
CONF_TOKEN: "abcde",
|
||||
}
|
||||
MOCK_CALLS_ENTRY_WS = {
|
||||
"host": "fake",
|
||||
"name": "HomeAssistant",
|
||||
"port": 8001,
|
||||
"timeout": 8,
|
||||
"token": "abcde",
|
||||
CONF_TOKEN: "123456789",
|
||||
}
|
||||
|
||||
ENTITY_ID_NOTURNON = f"{DOMAIN}.fake_noturnon"
|
||||
@@ -109,45 +106,6 @@ MOCK_CONFIG_NOTURNON = {
|
||||
}
|
||||
|
||||
|
||||
@pytest.fixture(name="remote")
|
||||
def remote_fixture():
|
||||
"""Patch the samsungctl Remote."""
|
||||
with patch(
|
||||
"homeassistant.components.samsungtv.bridge.Remote"
|
||||
) as remote_class, patch(
|
||||
"homeassistant.components.samsungtv.config_flow.socket"
|
||||
) as socket1, patch(
|
||||
"homeassistant.components.samsungtv.socket"
|
||||
) as socket2:
|
||||
remote = Mock()
|
||||
remote.__enter__ = Mock()
|
||||
remote.__exit__ = Mock()
|
||||
remote_class.return_value = remote
|
||||
socket1.gethostbyname.return_value = "FAKE_IP_ADDRESS"
|
||||
socket2.gethostbyname.return_value = "FAKE_IP_ADDRESS"
|
||||
yield remote
|
||||
|
||||
|
||||
@pytest.fixture(name="remotews")
|
||||
def remotews_fixture():
|
||||
"""Patch the samsungtvws SamsungTVWS."""
|
||||
with patch(
|
||||
"homeassistant.components.samsungtv.bridge.SamsungTVWS"
|
||||
) as remote_class, patch(
|
||||
"homeassistant.components.samsungtv.config_flow.socket"
|
||||
) as socket1, patch(
|
||||
"homeassistant.components.samsungtv.socket"
|
||||
) as socket2:
|
||||
remote = Mock()
|
||||
remote.__enter__ = Mock()
|
||||
remote.__exit__ = Mock()
|
||||
remote_class.return_value = remote
|
||||
remote_class().__enter__().token = "FAKE_TOKEN"
|
||||
socket1.gethostbyname.return_value = "FAKE_IP_ADDRESS"
|
||||
socket2.gethostbyname.return_value = "FAKE_IP_ADDRESS"
|
||||
yield remote
|
||||
|
||||
|
||||
@pytest.fixture(name="delay")
|
||||
def delay_fixture():
|
||||
"""Patch the delay script function."""
|
||||
@@ -226,7 +184,7 @@ async def test_setup_websocket_2(hass, mock_now):
|
||||
state = hass.states.get(entity_id)
|
||||
assert state
|
||||
assert remote.call_count == 1
|
||||
assert remote.call_args_list == [call(**MOCK_CALLS_ENTRY_WS)]
|
||||
assert remote.call_args_list == [call(**MOCK_CALLS_WS)]
|
||||
|
||||
|
||||
async def test_update_on(hass, remote, mock_now):
|
||||
@@ -272,12 +230,18 @@ async def test_update_access_denied(hass, remote, mock_now):
|
||||
with patch("homeassistant.util.dt.utcnow", return_value=next_update):
|
||||
async_fire_time_changed(hass, next_update)
|
||||
await hass.async_block_till_done()
|
||||
next_update = mock_now + timedelta(minutes=10)
|
||||
with patch("homeassistant.util.dt.utcnow", return_value=next_update):
|
||||
async_fire_time_changed(hass, next_update)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert [
|
||||
flow
|
||||
for flow in hass.config_entries.flow.async_progress()
|
||||
if flow["context"]["source"] == "reauth"
|
||||
]
|
||||
state = hass.states.get(ENTITY_ID)
|
||||
assert state.state == STATE_UNAVAILABLE
|
||||
|
||||
|
||||
async def test_update_connection_failure(hass, remotews, mock_now):
|
||||
@@ -296,12 +260,18 @@ async def test_update_connection_failure(hass, remotews, mock_now):
|
||||
with patch("homeassistant.util.dt.utcnow", return_value=next_update):
|
||||
async_fire_time_changed(hass, next_update)
|
||||
await hass.async_block_till_done()
|
||||
next_update = mock_now + timedelta(minutes=10)
|
||||
with patch("homeassistant.util.dt.utcnow", return_value=next_update):
|
||||
async_fire_time_changed(hass, next_update)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert [
|
||||
flow
|
||||
for flow in hass.config_entries.flow.async_progress()
|
||||
if flow["context"]["source"] == "reauth"
|
||||
]
|
||||
state = hass.states.get(ENTITY_ID)
|
||||
assert state.state == STATE_UNAVAILABLE
|
||||
|
||||
|
||||
async def test_update_unhandled_response(hass, remote, mock_now):
|
||||
@@ -438,7 +408,8 @@ async def test_state_without_turnon(hass, remote):
|
||||
DOMAIN, SERVICE_TURN_OFF, {ATTR_ENTITY_ID: ENTITY_ID_NOTURNON}, True
|
||||
)
|
||||
state = hass.states.get(ENTITY_ID_NOTURNON)
|
||||
assert state.state == STATE_OFF
|
||||
# Should be STATE_UNAVAILABLE since there is no way to turn it back on
|
||||
assert state.state == STATE_UNAVAILABLE
|
||||
|
||||
|
||||
async def test_supported_features_with_turnon(hass, remote):
|
||||
@@ -555,6 +526,15 @@ async def test_media_play(hass, remote):
|
||||
assert remote.close.call_count == 1
|
||||
assert remote.close.call_args_list == [call()]
|
||||
|
||||
assert await hass.services.async_call(
|
||||
DOMAIN, SERVICE_MEDIA_PLAY_PAUSE, {ATTR_ENTITY_ID: ENTITY_ID}, True
|
||||
)
|
||||
# key and update called
|
||||
assert remote.control.call_count == 2
|
||||
assert remote.control.call_args_list == [call("KEY_PLAY"), call("KEY_PAUSE")]
|
||||
assert remote.close.call_count == 2
|
||||
assert remote.close.call_args_list == [call(), call()]
|
||||
|
||||
|
||||
async def test_media_pause(hass, remote):
|
||||
"""Test for media_pause."""
|
||||
@@ -568,6 +548,15 @@ async def test_media_pause(hass, remote):
|
||||
assert remote.close.call_count == 1
|
||||
assert remote.close.call_args_list == [call()]
|
||||
|
||||
assert await hass.services.async_call(
|
||||
DOMAIN, SERVICE_MEDIA_PLAY_PAUSE, {ATTR_ENTITY_ID: ENTITY_ID}, True
|
||||
)
|
||||
# key and update called
|
||||
assert remote.control.call_count == 2
|
||||
assert remote.control.call_args_list == [call("KEY_PAUSE"), call("KEY_PLAY")]
|
||||
assert remote.close.call_count == 2
|
||||
assert remote.close.call_args_list == [call(), call()]
|
||||
|
||||
|
||||
async def test_media_next_track(hass, remote):
|
||||
"""Test for media_next_track."""
|
||||
|
||||
Reference in New Issue
Block a user