From 2025afe14b18d35b186003057edbd44eec8bf47a Mon Sep 17 00:00:00 2001
From: Simone Chemelli <simone.chemelli@gmail.com>
Date: Mon, 26 Jul 2021 16:43:05 +0200
Subject: [PATCH] Add MAC to SamsungTV when missing (#53479)

* Add MAC when missing

* Fix I/O

* Add test for missing MAC address
---
 .../components/samsungtv/__init__.py          | 14 ++++--
 .../components/samsungtv/config_flow.py       |  3 ++
 .../components/samsungtv/manifest.json        |  1 +
 requirements_all.txt                          |  1 +
 requirements_test_all.txt                     |  1 +
 .../components/samsungtv/test_config_flow.py  | 49 +++++++++++++++++++
 6 files changed, 66 insertions(+), 3 deletions(-)

diff --git a/homeassistant/components/samsungtv/__init__.py b/homeassistant/components/samsungtv/__init__.py
index 09b513c3830..773c340d7b9 100644
--- a/homeassistant/components/samsungtv/__init__.py
+++ b/homeassistant/components/samsungtv/__init__.py
@@ -1,6 +1,8 @@
 """The Samsung TV integration."""
+from functools import partial
 import socket
 
+import getmac
 import voluptuous as vol
 
 from homeassistant import config_entries
@@ -140,13 +142,19 @@ async def _async_create_bridge_with_updated_data(hass, entry):
 
     bridge = _async_get_device_bridge({**entry.data, **updated_data})
 
-    if not entry.data.get(CONF_MAC) and bridge.method == METHOD_WEBSOCKET:
+    mac = entry.data.get(CONF_MAC)
+    if not mac and bridge.method == METHOD_WEBSOCKET:
         if info:
             mac = mac_from_device_info(info)
         else:
             mac = await hass.async_add_executor_job(bridge.mac_from_device)
-        if mac:
-            updated_data[CONF_MAC] = mac
+
+    if not mac:
+        mac = await hass.async_add_executor_job(
+            partial(getmac.get_mac_address, ip=host)
+        )
+    if mac:
+        updated_data[CONF_MAC] = mac
 
     if updated_data:
         data = {**entry.data, **updated_data}
diff --git a/homeassistant/components/samsungtv/config_flow.py b/homeassistant/components/samsungtv/config_flow.py
index 392beda6ac5..da13d0fe70c 100644
--- a/homeassistant/components/samsungtv/config_flow.py
+++ b/homeassistant/components/samsungtv/config_flow.py
@@ -2,6 +2,7 @@
 import socket
 from urllib.parse import urlparse
 
+import getmac
 import voluptuous as vol
 
 from homeassistant import config_entries, data_entry_flow
@@ -154,6 +155,8 @@ class SamsungTVConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
         self._udn = _strip_uuid(dev_info.get("udn", info["id"]))
         if mac := mac_from_device_info(info):
             self._mac = mac
+        elif mac := getmac.get_mac_address(ip=self._host):
+            self._mac = mac
         self._device_info = info
         return True
 
diff --git a/homeassistant/components/samsungtv/manifest.json b/homeassistant/components/samsungtv/manifest.json
index 133baccf4fb..36481b43756 100644
--- a/homeassistant/components/samsungtv/manifest.json
+++ b/homeassistant/components/samsungtv/manifest.json
@@ -3,6 +3,7 @@
   "name": "Samsung Smart TV",
   "documentation": "https://www.home-assistant.io/integrations/samsungtv",
   "requirements": [
+    "getmac==0.8.2",
     "samsungctl[websocket]==0.7.1",
     "samsungtvws==1.6.0",
     "wakeonlan==2.0.1"
diff --git a/requirements_all.txt b/requirements_all.txt
index 523bca15f47..47bc55074be 100644
--- a/requirements_all.txt
+++ b/requirements_all.txt
@@ -679,6 +679,7 @@ georss_qld_bushfire_alert_client==0.5
 # homeassistant.components.kef
 # homeassistant.components.minecraft_server
 # homeassistant.components.nmap_tracker
+# homeassistant.components.samsungtv
 getmac==0.8.2
 
 # homeassistant.components.gios
diff --git a/requirements_test_all.txt b/requirements_test_all.txt
index e2fd0df2fe0..f05af08862e 100644
--- a/requirements_test_all.txt
+++ b/requirements_test_all.txt
@@ -388,6 +388,7 @@ georss_qld_bushfire_alert_client==0.5
 # homeassistant.components.kef
 # homeassistant.components.minecraft_server
 # homeassistant.components.nmap_tracker
+# homeassistant.components.samsungtv
 getmac==0.8.2
 
 # homeassistant.components.gios
diff --git a/tests/components/samsungtv/test_config_flow.py b/tests/components/samsungtv/test_config_flow.py
index 4fe8ddc2b5e..64d0c95c084 100644
--- a/tests/components/samsungtv/test_config_flow.py
+++ b/tests/components/samsungtv/test_config_flow.py
@@ -797,6 +797,55 @@ async def test_autodetect_websocket(hass: HomeAssistant, remote: Mock, remotews:
     assert entries[0].data[CONF_MAC] == "aa:bb:cc:dd:ee:ff"
 
 
+async def test_websocket_no_mac(hass: HomeAssistant, remote: Mock, remotews: Mock):
+    """Test for send key with autodetection of protocol."""
+    with patch(
+        "homeassistant.components.samsungtv.bridge.Remote",
+        side_effect=OSError("Boom"),
+    ), patch(
+        "homeassistant.components.samsungtv.config_flow.socket.gethostbyname",
+        return_value="fake_host",
+    ), patch(
+        "homeassistant.components.samsungtv.bridge.SamsungTVWS"
+    ) as remotews, patch(
+        "getmac.get_mac_address", return_value="gg:hh:ii:ll:mm:nn"
+    ):
+        enter = Mock()
+        type(enter).token = PropertyMock(return_value="123456789")
+        remote = Mock()
+        remote.__enter__ = Mock(return_value=enter)
+        remote.__exit__ = Mock(return_value=False)
+        remote.rest_device_info.return_value = {
+            "id": "uuid:be9554b9-c9fb-41f4-8920-22da015376a4",
+            "device": {
+                "modelName": "82GXARRS",
+                "networkType": "lan",
+                "udn": "uuid:be9554b9-c9fb-41f4-8920-22da015376a4",
+                "name": "[TV] Living Room",
+                "type": "Samsung SmartTV",
+            },
+        }
+        remotews.return_value = remote
+
+        result = await hass.config_entries.flow.async_init(
+            DOMAIN, context={"source": config_entries.SOURCE_USER}, data=MOCK_USER_DATA
+        )
+        assert result["type"] == "create_entry"
+        assert result["data"][CONF_METHOD] == "websocket"
+        assert result["data"][CONF_TOKEN] == "123456789"
+        assert result["data"][CONF_MAC] == "gg:hh:ii:ll:mm:nn"
+        assert remotews.call_count == 2
+        assert remotews.call_args_list == [
+            call(**AUTODETECT_WEBSOCKET_SSL),
+            call(**DEVICEINFO_WEBSOCKET_SSL),
+        ]
+        await hass.async_block_till_done()
+
+    entries = hass.config_entries.async_entries(DOMAIN)
+    assert len(entries) == 1
+    assert entries[0].data[CONF_MAC] == "gg:hh:ii:ll:mm:nn"
+
+
 async def test_autodetect_auth_missing(hass: HomeAssistant, remote: Mock):
     """Test for send key with autodetection of protocol."""
     with patch(
-- 
GitLab