Add samsungtv dhcp and zeroconf discovery (#48022)

Co-authored-by: J. Nick Koston <nick@koston.org>
This commit is contained in:
Simone Chemelli
2021-05-22 17:41:18 +02:00
committed by GitHub
parent aa9b99713c
commit b9a0fb93eb
17 changed files with 1174 additions and 415 deletions

View File

@@ -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."""