Turn on samsungtv with wakeonlan (#50964)

If we have the mac address from discovery, we can use it to wake
the TV.  Currently the TV goes unavailable when you turn it off
as the only way to turn it back on is wake on lan or via the remote.

Users who are not using host networking can use a script instead.
This commit is contained in:
J. Nick Koston 2021-05-22 15:33:37 -05:00 committed by GitHub
parent f4289b3fca
commit 45897b59f2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 49 additions and 3 deletions

View file

@ -4,7 +4,8 @@
"documentation": "https://www.home-assistant.io/integrations/samsungtv",
"requirements": [
"samsungctl[websocket]==0.7.1",
"samsungtvws==1.6.0"
"samsungtvws==1.6.0",
"wakeonlan==2.0.1"
],
"ssdp": [
{

View file

@ -3,6 +3,7 @@ import asyncio
from datetime import timedelta
import voluptuous as vol
from wakeonlan import send_magic_packet
from homeassistant.components.media_player import DEVICE_CLASS_TV, MediaPlayerEntity
from homeassistant.components.media_player.const import (
@ -71,6 +72,7 @@ class SamsungTVDevice(MediaPlayerEntity):
def __init__(self, bridge, config_entry, on_script):
"""Initialize the Samsung device."""
self._config_entry = config_entry
self._host = config_entry.data[CONF_HOST]
self._mac = config_entry.data.get(CONF_MAC)
self._manufacturer = config_entry.data.get(CONF_MANUFACTURER)
self._model = config_entry.data.get(CONF_MODEL)
@ -146,7 +148,7 @@ class SamsungTVDevice(MediaPlayerEntity):
"""Return the availability of the device."""
if self._auth_failed:
return False
return self._state == STATE_ON or self._on_script
return self._state == STATE_ON or self._on_script or self._mac
@property
def device_info(self):
@ -174,7 +176,7 @@ class SamsungTVDevice(MediaPlayerEntity):
@property
def supported_features(self):
"""Flag media player features that are supported."""
if self._on_script:
if self._on_script or self._mac:
return SUPPORT_SAMSUNGTV | SUPPORT_TURN_ON
return SUPPORT_SAMSUNGTV
@ -246,10 +248,19 @@ class SamsungTVDevice(MediaPlayerEntity):
await asyncio.sleep(KEY_PRESS_TIMEOUT, self.hass.loop)
await self.hass.async_add_executor_job(self.send_key, "KEY_ENTER")
def _wake_on_lan(self):
"""Wake the device via wake on lan."""
send_magic_packet(self._mac, ip_address=self._host)
# If the ip address changed since we last saw the device
# broadcast a packet as well
send_magic_packet(self._mac)
async def async_turn_on(self):
"""Turn the media player on."""
if self._on_script:
await self._on_script.async_run(context=self._context)
elif self._mac:
await self.hass.async_add_executor_job(self._wake_on_lan)
def select_source(self, source):
"""Select input source."""

View file

@ -2325,6 +2325,7 @@ vtjp==0.1.14
# homeassistant.components.vultr
vultr==0.1.2
# homeassistant.components.samsungtv
# homeassistant.components.wake_on_lan
wakeonlan==2.0.1

View file

@ -1249,6 +1249,7 @@ vsure==1.7.3
# homeassistant.components.vultr
vultr==0.1.2
# homeassistant.components.samsungtv
# homeassistant.components.wake_on_lan
wakeonlan==2.0.1

View file

@ -35,6 +35,7 @@ from homeassistant.const import (
ATTR_SUPPORTED_FEATURES,
CONF_HOST,
CONF_IP_ADDRESS,
CONF_MAC,
CONF_METHOD,
CONF_NAME,
CONF_PORT,
@ -98,6 +99,17 @@ MOCK_ENTRY_WS = {
CONF_TOKEN: "123456789",
}
MOCK_ENTRY_WS_WITH_MAC = {
CONF_IP_ADDRESS: "test",
CONF_HOST: "fake_host",
CONF_METHOD: "websocket",
CONF_MAC: "aa:bb:cc:dd:ee:ff",
CONF_NAME: "fake",
CONF_PORT: 8002,
CONF_TOKEN: "123456789",
}
ENTITY_ID_NOTURNON = f"{DOMAIN}.fake_noturnon"
MOCK_CONFIG_NOTURNON = {
SAMSUNGTV_DOMAIN: [
@ -593,6 +605,26 @@ async def test_turn_on_with_turnon(hass, remote, delay):
assert delay.call_count == 1
async def test_turn_on_wol(hass, remotews):
"""Test turn on."""
entry = MockConfigEntry(
domain=SAMSUNGTV_DOMAIN,
data=MOCK_ENTRY_WS_WITH_MAC,
unique_id="any",
)
entry.add_to_hass(hass)
assert await async_setup_component(hass, SAMSUNGTV_DOMAIN, {})
await hass.async_block_till_done()
with patch(
"homeassistant.components.samsungtv.media_player.send_magic_packet"
) as mock_send_magic_packet:
assert await hass.services.async_call(
DOMAIN, SERVICE_TURN_ON, {ATTR_ENTITY_ID: ENTITY_ID}, True
)
await hass.async_block_till_done()
assert mock_send_magic_packet.called
async def test_turn_on_without_turnon(hass, remote):
"""Test turn on."""
await setup_samsungtv(hass, MOCK_CONFIG_NOTURNON)