From 2836644eb9f5371098fb6f9cd3342af545902e48 Mon Sep 17 00:00:00 2001 From: On Freund Date: Sat, 4 Apr 2020 12:19:42 +0300 Subject: [PATCH 01/11] Samsung TV Options Flow skeleton --- .../components/samsungtv/config_flow.py | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/samsungtv/config_flow.py b/homeassistant/components/samsungtv/config_flow.py index 95283d9606cf88..35fe0ba3dd5f27 100644 --- a/homeassistant/components/samsungtv/config_flow.py +++ b/homeassistant/components/samsungtv/config_flow.py @@ -4,7 +4,7 @@ import voluptuous as vol -from homeassistant import config_entries +from homeassistant import config_entries, core from homeassistant.components.ssdp import ( ATTR_SSDP_LOCATION, ATTR_UPNP_MANUFACTURER, @@ -174,3 +174,17 @@ async def async_step_reauth(self, user_input=None): self.context["title_placeholders"] = {"model": self._title} return await self.async_step_confirm() + + @staticmethod + @core.callback + def async_get_options_flow(config_entry): + """Define the config flow to handle options.""" + return SamsungTVOptionsFlowHandler(config_entry) + + +class SamsungTVOptionsFlowHandler(config_entries.OptionsFlow): + """Handle a SamsungTV options flow.""" + + def __init__(self, config_entry): + """Initialize.""" + self.config_entry = config_entry From 3eb10a267fc329a9e67c412c2814786efed894dc Mon Sep 17 00:00:00 2001 From: On Freund Date: Thu, 9 Apr 2020 15:55:12 +0300 Subject: [PATCH 02/11] WoL with MAC address from options flow --- .../components/samsungtv/config_flow.py | 16 ++++++++++++++++ homeassistant/components/samsungtv/manifest.json | 3 ++- .../components/samsungtv/media_player.py | 15 ++++++++++++++- homeassistant/components/samsungtv/strings.json | 10 ++++++++++ requirements_all.txt | 1 + requirements_test_all.txt | 1 + 6 files changed, 44 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/samsungtv/config_flow.py b/homeassistant/components/samsungtv/config_flow.py index 35fe0ba3dd5f27..ed531d97d2819f 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 +from getmac import get_mac_address import voluptuous as vol from homeassistant import config_entries, core @@ -15,6 +16,7 @@ CONF_HOST, CONF_ID, CONF_IP_ADDRESS, + CONF_MAC, CONF_METHOD, CONF_NAME, CONF_PORT, @@ -188,3 +190,17 @@ class SamsungTVOptionsFlowHandler(config_entries.OptionsFlow): def __init__(self, config_entry): """Initialize.""" self.config_entry = config_entry + + async def async_step_init(self, user_input=None): + """Manage the options.""" + if user_input is not None: + return self.async_create_entry(title="", data=user_input) + + if CONF_MAC in self.config_entry.options: + current_mac = self.config_entry.options[CONF_MAC] + else: + hostname = self.config_entry.data[CONF_HOST] + current_mac = get_mac_address(hostname=hostname) + + schema = {vol.Optional(CONF_MAC, default=current_mac): str} + return self.async_show_form(step_id="init", data_schema=vol.Schema(schema)) diff --git a/homeassistant/components/samsungtv/manifest.json b/homeassistant/components/samsungtv/manifest.json index efcb9064208b66..e6ae0f421c0566 100644 --- a/homeassistant/components/samsungtv/manifest.json +++ b/homeassistant/components/samsungtv/manifest.json @@ -4,7 +4,8 @@ "documentation": "https://www.home-assistant.io/integrations/samsungtv", "requirements": [ "samsungctl[websocket]==0.7.1", - "samsungtvws[websocket]==1.4.0" + "samsungtvws[websocket]==1.4.0", + "getmac==0.8.1" ], "ssdp": [ { diff --git a/homeassistant/components/samsungtv/media_player.py b/homeassistant/components/samsungtv/media_player.py index 7eb0f50efc2b8c..ae2833c407a1f0 100644 --- a/homeassistant/components/samsungtv/media_player.py +++ b/homeassistant/components/samsungtv/media_player.py @@ -22,9 +22,12 @@ CONF_HOST, CONF_ID, CONF_IP_ADDRESS, + CONF_MAC, CONF_METHOD, CONF_NAME, CONF_PORT, + CONF_SERVICE, + CONF_SERVICE_DATA, CONF_TOKEN, STATE_OFF, STATE_ON, @@ -56,7 +59,17 @@ async def async_setup_entry(hass, config_entry, async_add_entities): """Set up the Samsung TV from a config entry.""" ip_address = config_entry.data[CONF_IP_ADDRESS] on_script = None - if ( + + if CONF_MAC in config_entry.options: + mac = config_entry.options[CONF_MAC] + script = cv.SCRIPT_SCHEMA( + { + CONF_SERVICE: "wake_on_lan.send_magic_packet", + CONF_SERVICE_DATA: {CONF_MAC: mac}, + } + ) + on_script = Script(hass, script) + elif ( DOMAIN in hass.data and ip_address in hass.data[DOMAIN] and CONF_ON_ACTION in hass.data[DOMAIN][ip_address] diff --git a/homeassistant/components/samsungtv/strings.json b/homeassistant/components/samsungtv/strings.json index 4377e0671e92f6..7fc269a17623cd 100644 --- a/homeassistant/components/samsungtv/strings.json +++ b/homeassistant/components/samsungtv/strings.json @@ -18,5 +18,15 @@ "not_successful": "Unable to connect to this Samsung TV device.", "not_supported": "This Samsung TV device is currently not supported." } + }, + "options": { + "step": { + "init": { + "title": "Configure MAC address", + "data": { + "mac": "MAC address" + } + } + } } } diff --git a/requirements_all.txt b/requirements_all.txt index 18c9f9ef407fab..65067219771338 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -620,6 +620,7 @@ georss_qld_bushfire_alert_client==0.3 # 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 30871402cd366b..ad526946637930 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -255,6 +255,7 @@ georss_qld_bushfire_alert_client==0.3 # homeassistant.components.kef # homeassistant.components.minecraft_server # homeassistant.components.nmap_tracker +# homeassistant.components.samsungtv getmac==0.8.2 # homeassistant.components.gios From e3e520522aeb3e01ebc5b94462ccacb7086b353c Mon Sep 17 00:00:00 2001 From: On Freund Date: Thu, 9 Apr 2020 18:32:58 +0300 Subject: [PATCH 03/11] Test samsung options flow --- .../components/samsungtv/config_flow.py | 8 +- .../components/samsungtv/test_config_flow.py | 78 ++++++++++++++++++- 2 files changed, 84 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/samsungtv/config_flow.py b/homeassistant/components/samsungtv/config_flow.py index ed531d97d2819f..ef589934363d90 100644 --- a/homeassistant/components/samsungtv/config_flow.py +++ b/homeassistant/components/samsungtv/config_flow.py @@ -1,4 +1,5 @@ """Config flow for Samsung TV.""" +from functools import partial import socket from urllib.parse import urlparse @@ -200,7 +201,12 @@ async def async_step_init(self, user_input=None): current_mac = self.config_entry.options[CONF_MAC] else: hostname = self.config_entry.data[CONF_HOST] - current_mac = get_mac_address(hostname=hostname) + try: + current_mac = await self.hass.async_add_executor_job( + partial(get_mac_address, **{"hostname": hostname}) + ) + except socket.gaierror: + current_mac = None schema = {vol.Optional(CONF_MAC, default=current_mac): str} return self.async_show_form(step_id="init", data_schema=vol.Schema(schema)) diff --git a/tests/components/samsungtv/test_config_flow.py b/tests/components/samsungtv/test_config_flow.py index 2673ee565599c7..c9eac849b1e8ff 100644 --- a/tests/components/samsungtv/test_config_flow.py +++ b/tests/components/samsungtv/test_config_flow.py @@ -1,4 +1,5 @@ """Tests for Samsung TV config flow.""" +import socket import pytest from samsungctl.exceptions import AccessDenied, UnhandledResponse from samsungtvws.exceptions import ConnectionFailure @@ -16,7 +17,16 @@ ATTR_UPNP_MODEL_NAME, ATTR_UPNP_UDN, ) -from homeassistant.const import CONF_HOST, CONF_ID, CONF_METHOD, CONF_NAME, CONF_TOKEN +from homeassistant.const import ( + CONF_HOST, + CONF_ID, + CONF_MAC, + CONF_METHOD, + CONF_NAME, + CONF_TOKEN, +) + +from tests.common import MockConfigEntry from tests.async_mock import DEFAULT as DEFAULT_MOCK, Mock, PropertyMock, call, patch @@ -571,3 +581,69 @@ async def test_autodetect_none(hass, remote, remotews): call(**AUTODETECT_WEBSOCKET_PLAIN), call(**AUTODETECT_WEBSOCKET_SSL), ] + + +async def test_options_with_obtained_mac(hass, remote): + """Test the options flow with obtained mac.""" + config_entry = MockConfigEntry(domain=DOMAIN, data={CONF_HOST: "hostname"},) + + config_entry.add_to_hass(hass) + + # by default, the mac address should be automatically obtained + with patch( + "homeassistant.components.samsungtv.config_flow.get_mac_address", + return_value="11:11:11", + ): + result = await hass.config_entries.options.async_init(config_entry.entry_id) + + assert result["type"] == "form" + assert result["step_id"] == "init" + + result = await hass.config_entries.options.async_configure( + result["flow_id"], user_input={}, + ) + + assert result["type"] == "create_entry" + assert config_entry.options[CONF_MAC] == "11:11:11" + + # override the auto-obtained mac address + result = await hass.config_entries.options.async_init(config_entry.entry_id) + + result = await hass.config_entries.options.async_configure( + result["flow_id"], user_input={CONF_MAC: "22:22:22"}, + ) + assert result["type"] == "create_entry" + assert config_entry.options[CONF_MAC] == "22:22:22" + + +async def test_options_without_obtained_mac(hass, remote): + """Test the options flow without obtained mac.""" + config_entry = MockConfigEntry(domain=DOMAIN, data={CONF_HOST: "hostname"},) + + config_entry.add_to_hass(hass) + + # simulate an error in getting the mac address + with patch( + "homeassistant.components.samsungtv.config_flow.get_mac_address", + side_effect=socket.gaierror, + ): + result = await hass.config_entries.options.async_init(config_entry.entry_id) + + assert result["type"] == "form" + assert result["step_id"] == "init" + + result = await hass.config_entries.options.async_configure( + result["flow_id"], user_input={}, + ) + + assert result["type"] == "create_entry" + assert config_entry.options[CONF_MAC] is None + + # override the auto-obtained mac address + result = await hass.config_entries.options.async_init(config_entry.entry_id) + + result = await hass.config_entries.options.async_configure( + result["flow_id"], user_input={CONF_MAC: "22:22:22"}, + ) + assert result["type"] == "create_entry" + assert config_entry.options[CONF_MAC] == "22:22:22" From 0569bdcf4161634d191caa34ef6d1c5145cba3a1 Mon Sep 17 00:00:00 2001 From: On Freund Date: Thu, 9 Apr 2020 19:02:32 +0300 Subject: [PATCH 04/11] Test on-script creation from mac --- .../components/samsungtv/media_player.py | 22 +++++++++++++------ .../components/samsungtv/test_media_player.py | 15 ++++++++++++- 2 files changed, 29 insertions(+), 8 deletions(-) diff --git a/homeassistant/components/samsungtv/media_player.py b/homeassistant/components/samsungtv/media_player.py index ae2833c407a1f0..fa75fd60e770f9 100644 --- a/homeassistant/components/samsungtv/media_player.py +++ b/homeassistant/components/samsungtv/media_player.py @@ -4,7 +4,9 @@ import voluptuous as vol +from homeassistant import core from homeassistant.components.media_player import DEVICE_CLASS_TV, MediaPlayerEntity + from homeassistant.components.media_player.const import ( MEDIA_TYPE_CHANNEL, SUPPORT_NEXT_TRACK, @@ -55,6 +57,18 @@ ) +@core.callback +def async_get_on_script_from_mac(hass, mac): + """Create an on script from a mac address.""" + script = cv.SCRIPT_SCHEMA( + { + CONF_SERVICE: "wake_on_lan.send_magic_packet", + CONF_SERVICE_DATA: {CONF_MAC: mac}, + } + ) + return Script(hass, script) + + async def async_setup_entry(hass, config_entry, async_add_entities): """Set up the Samsung TV from a config entry.""" ip_address = config_entry.data[CONF_IP_ADDRESS] @@ -62,13 +76,7 @@ async def async_setup_entry(hass, config_entry, async_add_entities): if CONF_MAC in config_entry.options: mac = config_entry.options[CONF_MAC] - script = cv.SCRIPT_SCHEMA( - { - CONF_SERVICE: "wake_on_lan.send_magic_packet", - CONF_SERVICE_DATA: {CONF_MAC: mac}, - } - ) - on_script = Script(hass, script) + on_script = async_get_on_script_from_mac(hass, mac) elif ( DOMAIN in hass.data and ip_address in hass.data[DOMAIN] diff --git a/tests/components/samsungtv/test_media_player.py b/tests/components/samsungtv/test_media_player.py index 15ac13c64d5926..f0857f8e1c19d5 100644 --- a/tests/components/samsungtv/test_media_player.py +++ b/tests/components/samsungtv/test_media_player.py @@ -25,7 +25,10 @@ CONF_ON_ACTION, DOMAIN as SAMSUNGTV_DOMAIN, ) -from homeassistant.components.samsungtv.media_player import SUPPORT_SAMSUNGTV +from homeassistant.components.samsungtv.media_player import ( + SUPPORT_SAMSUNGTV, + async_get_on_script_from_mac, +) from homeassistant.const import ( ATTR_DEVICE_CLASS, ATTR_ENTITY_ID, @@ -742,3 +745,13 @@ async def test_select_source_invalid_source(hass, remote): assert remote.control.call_count == 0 assert remote.close.call_count == 0 assert remote.call_count == 1 + + +async def test_on_script_from_mac(hass, remote): + """Test creation of on-script from mac address.""" + + result = async_get_on_script_from_mac(hass, "11:11:11") + + assert len(result.sequence) == 1 + assert result.sequence[0]["service"] == "wake_on_lan.send_magic_packet" + assert result.sequence[0]["data"] == {"mac": "11:11:11"} From 23e31fa5df69ff0e2616d66ed52a7850b2ffb1ab Mon Sep 17 00:00:00 2001 From: On Freund Date: Fri, 10 Apr 2020 10:27:13 +0300 Subject: [PATCH 05/11] Allow removal of mac address --- .../components/samsungtv/config_flow.py | 4 +++- .../components/samsungtv/test_config_flow.py | 24 +++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/samsungtv/config_flow.py b/homeassistant/components/samsungtv/config_flow.py index ef589934363d90..7481b30fa52486 100644 --- a/homeassistant/components/samsungtv/config_flow.py +++ b/homeassistant/components/samsungtv/config_flow.py @@ -195,6 +195,8 @@ def __init__(self, config_entry): async def async_step_init(self, user_input=None): """Manage the options.""" if user_input is not None: + if user_input[CONF_MAC].strip() == "": + user_input.pop(CONF_MAC, None) return self.async_create_entry(title="", data=user_input) if CONF_MAC in self.config_entry.options: @@ -206,7 +208,7 @@ async def async_step_init(self, user_input=None): partial(get_mac_address, **{"hostname": hostname}) ) except socket.gaierror: - current_mac = None + current_mac = "" schema = {vol.Optional(CONF_MAC, default=current_mac): str} return self.async_show_form(step_id="init", data_schema=vol.Schema(schema)) diff --git a/tests/components/samsungtv/test_config_flow.py b/tests/components/samsungtv/test_config_flow.py index c9eac849b1e8ff..3b1cfe28eae1ab 100644 --- a/tests/components/samsungtv/test_config_flow.py +++ b/tests/components/samsungtv/test_config_flow.py @@ -647,3 +647,27 @@ async def test_options_without_obtained_mac(hass, remote): ) assert result["type"] == "create_entry" assert config_entry.options[CONF_MAC] == "22:22:22" + + +async def test_options_with_empty_mac(hass, remote): + """Test the options flow with an empty string for mac.""" + config_entry = MockConfigEntry(domain=DOMAIN, data={CONF_HOST: "hostname"},) + + config_entry.add_to_hass(hass) + + # simulate an error in getting the mac address + with patch( + "homeassistant.components.samsungtv.config_flow.get_mac_address", + return_value="11:11:11", + ): + result = await hass.config_entries.options.async_init(config_entry.entry_id) + + assert result["type"] == "form" + assert result["step_id"] == "init" + + result = await hass.config_entries.options.async_configure( + result["flow_id"], user_input={CONF_MAC: " "}, + ) + + assert result["type"] == "create_entry" + assert config_entry.options.get(CONF_MAC) is None From 4b81515b663ca2f082d86dd199f5413f5d50d16d Mon Sep 17 00:00:00 2001 From: On Freund Date: Fri, 17 Apr 2020 23:39:01 +0300 Subject: [PATCH 06/11] Fix handling of socket errors --- homeassistant/components/samsungtv/config_flow.py | 3 ++- tests/components/samsungtv/test_config_flow.py | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/samsungtv/config_flow.py b/homeassistant/components/samsungtv/config_flow.py index 7481b30fa52486..6d7019cda6c17b 100644 --- a/homeassistant/components/samsungtv/config_flow.py +++ b/homeassistant/components/samsungtv/config_flow.py @@ -207,7 +207,8 @@ async def async_step_init(self, user_input=None): current_mac = await self.hass.async_add_executor_job( partial(get_mac_address, **{"hostname": hostname}) ) - except socket.gaierror: + except OSError: + LOGGER.info("Could not find mac address for %s", hostname) current_mac = "" schema = {vol.Optional(CONF_MAC, default=current_mac): str} diff --git a/tests/components/samsungtv/test_config_flow.py b/tests/components/samsungtv/test_config_flow.py index 3b1cfe28eae1ab..fb96ebec0d39ae 100644 --- a/tests/components/samsungtv/test_config_flow.py +++ b/tests/components/samsungtv/test_config_flow.py @@ -625,7 +625,7 @@ async def test_options_without_obtained_mac(hass, remote): # simulate an error in getting the mac address with patch( "homeassistant.components.samsungtv.config_flow.get_mac_address", - side_effect=socket.gaierror, + side_effect=socket.gaierror(), ): result = await hass.config_entries.options.async_init(config_entry.entry_id) @@ -637,7 +637,7 @@ async def test_options_without_obtained_mac(hass, remote): ) assert result["type"] == "create_entry" - assert config_entry.options[CONF_MAC] is None + assert config_entry.options.get(CONF_MAC) is None # override the auto-obtained mac address result = await hass.config_entries.options.async_init(config_entry.entry_id) From 70a893b10198b5068ff363cd61cc28412f0c782c Mon Sep 17 00:00:00 2001 From: On Freund Date: Fri, 17 Apr 2020 23:49:34 +0300 Subject: [PATCH 07/11] Upgrade getmac --- homeassistant/components/samsungtv/manifest.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/samsungtv/manifest.json b/homeassistant/components/samsungtv/manifest.json index e6ae0f421c0566..0ceb847a444555 100644 --- a/homeassistant/components/samsungtv/manifest.json +++ b/homeassistant/components/samsungtv/manifest.json @@ -5,7 +5,7 @@ "requirements": [ "samsungctl[websocket]==0.7.1", "samsungtvws[websocket]==1.4.0", - "getmac==0.8.1" + "getmac==0.8.2" ], "ssdp": [ { From 336edd1251aac0ed66632029d8c1827f42b78384 Mon Sep 17 00:00:00 2001 From: On Freund Date: Thu, 30 Apr 2020 17:27:57 +0300 Subject: [PATCH 08/11] Add tests for async_setup_entry --- .../components/samsungtv/test_media_player.py | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/tests/components/samsungtv/test_media_player.py b/tests/components/samsungtv/test_media_player.py index f0857f8e1c19d5..851da3db895de9 100644 --- a/tests/components/samsungtv/test_media_player.py +++ b/tests/components/samsungtv/test_media_player.py @@ -104,6 +104,8 @@ "token": "abcde", } +MOCK_OPTIONS = {"mac": "11:11:11"} + ENTITY_ID_NOTURNON = f"{DOMAIN}.fake_noturnon" MOCK_CONFIG_NOTURNON = { SAMSUNGTV_DOMAIN: [ @@ -755,3 +757,43 @@ async def test_on_script_from_mac(hass, remote): assert len(result.sequence) == 1 assert result.sequence[0]["service"] == "wake_on_lan.send_magic_packet" assert result.sequence[0]["data"] == {"mac": "11:11:11"} + + +async def test_setup_with_options(hass, remote): + """Test setup with mac address in options.""" + entity_id = f"{DOMAIN}.fake" + entry = MockConfigEntry( + domain=SAMSUNGTV_DOMAIN, + data=MOCK_ENTRY_WS, + unique_id=entity_id, + options=MOCK_OPTIONS, + ) + entry.add_to_hass(hass) + + with patch( + "homeassistant.components.samsungtv.media_player.async_get_on_script_from_mac" + ) as on_script: + await async_setup_component(hass, SAMSUNGTV_DOMAIN, {}) + # await hass.config_entries.async_setup(entry.entry_id) + await hass.async_block_till_done() + + assert on_script.call_count == 1 + assert on_script.call_args_list == [call(hass, MOCK_OPTIONS["mac"])] + + +async def test_setup_without_options(hass, remote): + """Test setup without mac address in options.""" + entity_id = f"{DOMAIN}.fake" + entry = MockConfigEntry( + domain=SAMSUNGTV_DOMAIN, data=MOCK_ENTRY_WS, unique_id=entity_id + ) + entry.add_to_hass(hass) + + with patch( + "homeassistant.components.samsungtv.media_player.async_get_on_script_from_mac" + ) as on_script: + await async_setup_component(hass, SAMSUNGTV_DOMAIN, {}) + # await hass.config_entries.async_setup(entry.entry_id) + await hass.async_block_till_done() + + assert on_script.call_count == 0 From 0fa89eb3f143117c94f4b355cecacc858a071d7e Mon Sep 17 00:00:00 2001 From: On Freund Date: Thu, 30 Apr 2020 17:42:40 +0300 Subject: [PATCH 09/11] Fix isort Looks like the isort settings changed, so even tough this file wasn't touched, it still needs changing. --- homeassistant/components/samsungtv/media_player.py | 1 - 1 file changed, 1 deletion(-) diff --git a/homeassistant/components/samsungtv/media_player.py b/homeassistant/components/samsungtv/media_player.py index fa75fd60e770f9..609be5f34dc0c2 100644 --- a/homeassistant/components/samsungtv/media_player.py +++ b/homeassistant/components/samsungtv/media_player.py @@ -6,7 +6,6 @@ from homeassistant import core from homeassistant.components.media_player import DEVICE_CLASS_TV, MediaPlayerEntity - from homeassistant.components.media_player.const import ( MEDIA_TYPE_CHANNEL, SUPPORT_NEXT_TRACK, From ade860caaf82d0653bccc068fe60218abc3decb9 Mon Sep 17 00:00:00 2001 From: On Freund Date: Fri, 1 May 2020 15:16:04 +0300 Subject: [PATCH 10/11] Use suggestd value instead of default --- homeassistant/components/samsungtv/config_flow.py | 6 ++++-- tests/components/samsungtv/test_config_flow.py | 7 +++---- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/homeassistant/components/samsungtv/config_flow.py b/homeassistant/components/samsungtv/config_flow.py index 6d7019cda6c17b..ddb0ec48afcc16 100644 --- a/homeassistant/components/samsungtv/config_flow.py +++ b/homeassistant/components/samsungtv/config_flow.py @@ -195,7 +195,7 @@ def __init__(self, config_entry): async def async_step_init(self, user_input=None): """Manage the options.""" if user_input is not None: - if user_input[CONF_MAC].strip() == "": + if CONF_MAC not in user_input or user_input[CONF_MAC].strip() == "": user_input.pop(CONF_MAC, None) return self.async_create_entry(title="", data=user_input) @@ -211,5 +211,7 @@ async def async_step_init(self, user_input=None): LOGGER.info("Could not find mac address for %s", hostname) current_mac = "" - schema = {vol.Optional(CONF_MAC, default=current_mac): str} + schema = { + vol.Optional(CONF_MAC, description={"suggested_value": current_mac}): str + } return self.async_show_form(step_id="init", data_schema=vol.Schema(schema)) diff --git a/tests/components/samsungtv/test_config_flow.py b/tests/components/samsungtv/test_config_flow.py index fb96ebec0d39ae..d30a89fdddbe10 100644 --- a/tests/components/samsungtv/test_config_flow.py +++ b/tests/components/samsungtv/test_config_flow.py @@ -1,5 +1,6 @@ """Tests for Samsung TV config flow.""" import socket + import pytest from samsungctl.exceptions import AccessDenied, UnhandledResponse from samsungtvws.exceptions import ConnectionFailure @@ -26,9 +27,8 @@ CONF_TOKEN, ) -from tests.common import MockConfigEntry - from tests.async_mock import DEFAULT as DEFAULT_MOCK, Mock, PropertyMock, call, patch +from tests.common import MockConfigEntry MOCK_USER_DATA = {CONF_HOST: "fake_host", CONF_NAME: "fake_name"} MOCK_SSDP_DATA = { @@ -604,7 +604,7 @@ async def test_options_with_obtained_mac(hass, remote): ) assert result["type"] == "create_entry" - assert config_entry.options[CONF_MAC] == "11:11:11" + assert config_entry.options.get(CONF_MAC) is None # override the auto-obtained mac address result = await hass.config_entries.options.async_init(config_entry.entry_id) @@ -639,7 +639,6 @@ async def test_options_without_obtained_mac(hass, remote): assert result["type"] == "create_entry" assert config_entry.options.get(CONF_MAC) is None - # override the auto-obtained mac address result = await hass.config_entries.options.async_init(config_entry.entry_id) result = await hass.config_entries.options.async_configure( From 485b8a3e8b760865490162f6c896afb76cdb04b0 Mon Sep 17 00:00:00 2001 From: On Freund Date: Fri, 1 May 2020 15:17:13 +0300 Subject: [PATCH 11/11] Hanlde reloading of SamsungTV integration --- .../components/samsungtv/__init__.py | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/homeassistant/components/samsungtv/__init__.py b/homeassistant/components/samsungtv/__init__.py index 8c17ff4794c830..bbb52b00792a6f 100644 --- a/homeassistant/components/samsungtv/__init__.py +++ b/homeassistant/components/samsungtv/__init__.py @@ -9,6 +9,8 @@ from .const import CONF_ON_ACTION, DEFAULT_NAME, DOMAIN +UNDO_UPDATE_LISTENER = "update_update_listener" + def ensure_unique_hosts(value): """Validate that all configs have a unique host.""" @@ -62,8 +64,33 @@ async def async_setup(hass, config): async def async_setup_entry(hass, entry): """Set up the Samsung TV platform.""" + undo_listener = entry.add_update_listener(_update_listener) + + hass.data.setdefault(DOMAIN, {}) + hass.data[DOMAIN][entry.entry_id] = { + UNDO_UPDATE_LISTENER: undo_listener, + } + hass.async_create_task( hass.config_entries.async_forward_entry_setup(entry, MP_DOMAIN) ) return True + + +async def async_unload_entry(hass, entry): + """Unload a config entry.""" + unload_ok = await hass.async_create_task( + hass.config_entries.async_forward_entry_unload(entry, MP_DOMAIN) + ) + + if unload_ok: + hass.data[DOMAIN][entry.entry_id][UNDO_UPDATE_LISTENER]() + hass.data[DOMAIN].pop(entry.entry_id) + + return unload_ok + + +async def _update_listener(hass, entry): + """Handle options update.""" + await hass.config_entries.async_reload(entry.entry_id)