From cb63a9d7e17af0f243cbc34458b1452098846168 Mon Sep 17 00:00:00 2001
From: Jay Newstrom <jaynewstrom@gmail.com>
Date: Sun, 17 Nov 2019 06:17:22 -0600
Subject: [PATCH] Add broadcast address for WOL and samsungtv (#28819)

* Add broadcast address for WOL and samsungtv

* Fix style

* Fix tests, and add new test for new functionality

* Fix code style
---
 .../components/samsungtv/media_player.py      | 14 +++++++--
 .../components/samsungtv/test_media_player.py | 31 ++++++++++++++++++-
 2 files changed, 41 insertions(+), 4 deletions(-)

diff --git a/homeassistant/components/samsungtv/media_player.py b/homeassistant/components/samsungtv/media_player.py
index 65805235f3f..1262c3d7d36 100644
--- a/homeassistant/components/samsungtv/media_player.py
+++ b/homeassistant/components/samsungtv/media_player.py
@@ -26,6 +26,7 @@ from homeassistant.components.media_player.const import (
     SUPPORT_VOLUME_STEP,
 )
 from homeassistant.const import (
+    CONF_BROADCAST_ADDRESS,
     CONF_HOST,
     CONF_MAC,
     CONF_NAME,
@@ -41,6 +42,7 @@ from .const import LOGGER
 
 DEFAULT_NAME = "Samsung TV Remote"
 DEFAULT_TIMEOUT = 1
+DEFAULT_BROADCAST_ADDRESS = "255.255.255.255"
 
 KEY_PRESS_TIMEOUT = 1.2
 KNOWN_DEVICES_KEY = "samsungtv_known_devices"
@@ -65,6 +67,9 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
         vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
         vol.Optional(CONF_PORT): cv.port,
         vol.Optional(CONF_MAC): cv.string,
+        vol.Optional(
+            CONF_BROADCAST_ADDRESS, default=DEFAULT_BROADCAST_ADDRESS
+        ): cv.string,
         vol.Optional(CONF_TIMEOUT, default=DEFAULT_TIMEOUT): cv.positive_int,
     }
 )
@@ -84,6 +89,7 @@ def setup_platform(hass, config, add_entities, discovery_info=None):
         port = config.get(CONF_PORT)
         name = config.get(CONF_NAME)
         mac = config.get(CONF_MAC)
+        broadcast = config.get(CONF_BROADCAST_ADDRESS)
         timeout = config.get(CONF_TIMEOUT)
     elif discovery_info is not None:
         tv_name = discovery_info.get("name")
@@ -95,6 +101,7 @@ def setup_platform(hass, config, add_entities, discovery_info=None):
         port = None
         timeout = DEFAULT_TIMEOUT
         mac = None
+        broadcast = DEFAULT_BROADCAST_ADDRESS
         uuid = discovery_info.get("udn")
         if uuid and uuid.startswith("uuid:"):
             uuid = uuid[len("uuid:") :]
@@ -104,7 +111,7 @@ def setup_platform(hass, config, add_entities, discovery_info=None):
     ip_addr = socket.gethostbyname(host)
     if ip_addr not in known_devices:
         known_devices.add(ip_addr)
-        add_entities([SamsungTVDevice(host, port, name, timeout, mac, uuid)])
+        add_entities([SamsungTVDevice(host, port, name, timeout, mac, broadcast, uuid)])
         LOGGER.info("Samsung TV %s added as '%s'", host, name)
     else:
         LOGGER.info("Ignoring duplicate Samsung TV %s", host)
@@ -113,12 +120,13 @@ def setup_platform(hass, config, add_entities, discovery_info=None):
 class SamsungTVDevice(MediaPlayerDevice):
     """Representation of a Samsung TV."""
 
-    def __init__(self, host, port, name, timeout, mac, uuid):
+    def __init__(self, host, port, name, timeout, mac, broadcast, uuid):
         """Initialize the Samsung device."""
 
         # Save a reference to the imported classes
         self._name = name
         self._mac = mac
+        self._broadcast = broadcast
         self._uuid = uuid
         # Assume that the TV is not muted
         self._muted = False
@@ -339,7 +347,7 @@ class SamsungTVDevice(MediaPlayerDevice):
     def turn_on(self):
         """Turn the media player on."""
         if self._mac:
-            wakeonlan.send_magic_packet(self._mac)
+            wakeonlan.send_magic_packet(self._mac, ip_address=self._broadcast)
         else:
             self.send_key("KEY_POWERON")
 
diff --git a/tests/components/samsungtv/test_media_player.py b/tests/components/samsungtv/test_media_player.py
index 3409e55a49c..8f6014463f5 100644
--- a/tests/components/samsungtv/test_media_player.py
+++ b/tests/components/samsungtv/test_media_player.py
@@ -32,6 +32,7 @@ from homeassistant.const import (
     ATTR_ENTITY_ID,
     ATTR_FRIENDLY_NAME,
     ATTR_SUPPORTED_FEATURES,
+    CONF_BROADCAST_ADDRESS,
     CONF_HOST,
     CONF_MAC,
     CONF_NAME,
@@ -67,6 +68,19 @@ MOCK_CONFIG = {
     }
 }
 
+ENTITY_ID_BROADCAST = f"{DOMAIN}.fake_broadcast"
+MOCK_CONFIG_BROADCAST = {
+    DOMAIN: {
+        CONF_PLATFORM: SAMSUNGTV_DOMAIN,
+        CONF_HOST: "fake_broadcast",
+        CONF_NAME: "fake_broadcast",
+        CONF_PORT: 8001,
+        CONF_TIMEOUT: 10,
+        CONF_MAC: "38:f9:d3:82:b4:f1",
+        CONF_BROADCAST_ADDRESS: "192.168.5.255",
+    }
+}
+
 ENTITY_ID_NOMAC = f"{DOMAIN}.fake_nomac"
 MOCK_CONFIG_NOMAC = {
     DOMAIN: {
@@ -565,7 +579,22 @@ async def test_turn_on_with_mac(hass, remote, wakeonlan):
     )
     # key and update called
     assert wakeonlan.send_magic_packet.call_count == 1
-    assert wakeonlan.send_magic_packet.call_args_list == [call("38:f9:d3:82:b4:f1")]
+    assert wakeonlan.send_magic_packet.call_args_list == [
+        call("38:f9:d3:82:b4:f1", ip_address="255.255.255.255")
+    ]
+
+
+async def test_turn_on_with_mac_and_broadcast(hass, remote, wakeonlan):
+    """Test turn on."""
+    await setup_samsungtv(hass, MOCK_CONFIG_BROADCAST)
+    assert await hass.services.async_call(
+        DOMAIN, SERVICE_TURN_ON, {ATTR_ENTITY_ID: ENTITY_ID_BROADCAST}, True
+    )
+    # key and update called
+    assert wakeonlan.send_magic_packet.call_count == 1
+    assert wakeonlan.send_magic_packet.call_args_list == [
+        call("38:f9:d3:82:b4:f1", ip_address="192.168.5.255")
+    ]
 
 
 async def test_turn_on_without_mac(hass, remote):
-- 
GitLab