From 45b28b8b00e43f033c1ffce0655e3a791e2424dc Mon Sep 17 00:00:00 2001 From: Quentame Date: Thu, 9 Apr 2020 16:06:01 +0200 Subject: [PATCH] Add local_ip unique_id & icon and single_instance_allowed (#33483) * Add config flow + sensor unique_id & icon to local_ip * single_instance_allowed * Fix test * Martin's review * Name deprecated --- .../components/local_ip/.translations/en.json | 2 +- homeassistant/components/local_ip/__init__.py | 18 ++++++----- .../components/local_ip/config_flow.py | 21 +++++-------- homeassistant/components/local_ip/const.py | 6 ++++ homeassistant/components/local_ip/sensor.py | 20 ++++++++++--- .../components/local_ip/strings.json | 2 +- tests/components/local_ip/test_config_flow.py | 30 ++++++++++++++----- tests/components/local_ip/test_init.py | 4 +-- 8 files changed, 66 insertions(+), 37 deletions(-) create mode 100644 homeassistant/components/local_ip/const.py diff --git a/homeassistant/components/local_ip/.translations/en.json b/homeassistant/components/local_ip/.translations/en.json index 869bb5a23d5..69cbaa457d5 100644 --- a/homeassistant/components/local_ip/.translations/en.json +++ b/homeassistant/components/local_ip/.translations/en.json @@ -1,7 +1,7 @@ { "config": { "abort": { - "already_configured": "Integration is already configured with an existing sensor with that name" + "single_instance_allowed": "Only a single configuration of Local IP is allowed." }, "step": { "user": { diff --git a/homeassistant/components/local_ip/__init__.py b/homeassistant/components/local_ip/__init__.py index c93b7a5a81b..f787c028762 100644 --- a/homeassistant/components/local_ip/__init__.py +++ b/homeassistant/components/local_ip/__init__.py @@ -1,16 +1,20 @@ """Get the local IP address of the Home Assistant instance.""" import voluptuous as vol -from homeassistant import config_entries +from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry from homeassistant.const import CONF_NAME from homeassistant.core import HomeAssistant import homeassistant.helpers.config_validation as cv -DOMAIN = "local_ip" -PLATFORM = "sensor" +from .const import DOMAIN, PLATFORM CONFIG_SCHEMA = vol.Schema( - {DOMAIN: vol.Schema({vol.Optional(CONF_NAME, default=DOMAIN): cv.string})}, + { + DOMAIN: vol.All( + cv.deprecated(CONF_NAME, invalidation_version="0.110"), + vol.Schema({vol.Optional(CONF_NAME, default=DOMAIN): cv.string}), + ) + }, extra=vol.ALLOW_EXTRA, ) @@ -21,14 +25,14 @@ async def async_setup(hass: HomeAssistant, config: dict): if conf: hass.async_create_task( hass.config_entries.flow.async_init( - DOMAIN, data=conf, context={"source": config_entries.SOURCE_IMPORT} + DOMAIN, data=conf, context={"source": SOURCE_IMPORT} ) ) return True -async def async_setup_entry(hass: HomeAssistant, entry: config_entries.ConfigEntry): +async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry): """Set up local_ip from a config entry.""" hass.async_create_task( hass.config_entries.async_forward_entry_setup(entry, PLATFORM) @@ -37,6 +41,6 @@ async def async_setup_entry(hass: HomeAssistant, entry: config_entries.ConfigEnt return True -async def async_unload_entry(hass: HomeAssistant, entry: config_entries.ConfigEntry): +async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry): """Unload a config entry.""" return await hass.config_entries.async_forward_entry_unload(entry, PLATFORM) diff --git a/homeassistant/components/local_ip/config_flow.py b/homeassistant/components/local_ip/config_flow.py index 58a666a68f3..7d563cae7c4 100644 --- a/homeassistant/components/local_ip/config_flow.py +++ b/homeassistant/components/local_ip/config_flow.py @@ -1,9 +1,8 @@ """Config flow for local_ip.""" -import voluptuous as vol from homeassistant import config_entries -from . import DOMAIN +from .const import DOMAIN class SimpleConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): @@ -14,20 +13,14 @@ class SimpleConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): async def async_step_user(self, user_input=None): """Handle the initial step.""" - if user_input is not None: - if any( - user_input["name"] == entry.data["name"] - for entry in self._async_current_entries() - ): - return self.async_abort(reason="already_configured") - return self.async_create_entry(title=user_input["name"], data=user_input) + if self._async_current_entries(): + return self.async_abort(reason="single_instance_allowed") - return self.async_show_form( - step_id="user", - data_schema=vol.Schema({vol.Required("name", default=DOMAIN): str}), - errors={}, - ) + if user_input is None: + return self.async_show_form(step_id="user") + + return self.async_create_entry(title=DOMAIN, data=user_input) async def async_step_import(self, import_info): """Handle import from config file.""" diff --git a/homeassistant/components/local_ip/const.py b/homeassistant/components/local_ip/const.py new file mode 100644 index 00000000000..e18246a9730 --- /dev/null +++ b/homeassistant/components/local_ip/const.py @@ -0,0 +1,6 @@ +"""Local IP constants.""" + +DOMAIN = "local_ip" +PLATFORM = "sensor" + +SENSOR = "address" diff --git a/homeassistant/components/local_ip/sensor.py b/homeassistant/components/local_ip/sensor.py index 274a11faec6..d159b641fa2 100644 --- a/homeassistant/components/local_ip/sensor.py +++ b/homeassistant/components/local_ip/sensor.py @@ -1,20 +1,22 @@ """Sensor platform for local_ip.""" -from homeassistant.core import HomeAssistant +from homeassistant.const import CONF_NAME from homeassistant.helpers.entity import Entity from homeassistant.util import get_local_ip +from .const import DOMAIN, SENSOR -async def async_setup_entry(hass: HomeAssistant, config_entry, async_add_entities): + +async def async_setup_entry(hass, config_entry, async_add_entities): """Set up the platform from config_entry.""" - name = config_entry.data["name"] + name = config_entry.data.get(CONF_NAME) or DOMAIN async_add_entities([IPSensor(name)], True) class IPSensor(Entity): """A simple sensor.""" - def __init__(self, name: str): + def __init__(self, name): """Initialize the sensor.""" self._state = None self._name = name @@ -24,11 +26,21 @@ class IPSensor(Entity): """Return the name of the sensor.""" return self._name + @property + def unique_id(self): + """Return the unique id of the sensor.""" + return SENSOR + @property def state(self): """Return the state of the sensor.""" return self._state + @property + def icon(self): + """Return the icon of the sensor.""" + return "mdi:ip" + def update(self): """Fetch new state data for the sensor.""" self._state = get_local_ip() diff --git a/homeassistant/components/local_ip/strings.json b/homeassistant/components/local_ip/strings.json index 43a88be3325..f8e907b46d5 100644 --- a/homeassistant/components/local_ip/strings.json +++ b/homeassistant/components/local_ip/strings.json @@ -10,7 +10,7 @@ } }, "abort": { - "already_configured": "Integration is already configured with an existing sensor with that name" + "single_instance_allowed": "Only a single configuration of Local IP is allowed." } } } diff --git a/tests/components/local_ip/test_config_flow.py b/tests/components/local_ip/test_config_flow.py index f355e5c75b2..f6b3ebf6c8e 100644 --- a/tests/components/local_ip/test_config_flow.py +++ b/tests/components/local_ip/test_config_flow.py @@ -1,19 +1,33 @@ """Tests for the local_ip config_flow.""" -from homeassistant.components.local_ip import DOMAIN +from homeassistant import data_entry_flow +from homeassistant.components.local_ip.const import DOMAIN +from homeassistant.config_entries import SOURCE_USER + +from tests.common import MockConfigEntry async def test_config_flow(hass): """Test we can finish a config flow.""" result = await hass.config_entries.flow.async_init( - DOMAIN, context={"source": "user"} + DOMAIN, context={"source": SOURCE_USER} ) - assert result["type"] == "form" + assert result["type"] == data_entry_flow.RESULT_TYPE_FORM - result = await hass.config_entries.flow.async_configure( - result["flow_id"], {"name": "test"} - ) - assert result["type"] == "create_entry" + result = await hass.config_entries.flow.async_configure(result["flow_id"], {}) + assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY await hass.async_block_till_done() - state = hass.states.get("sensor.test") + state = hass.states.get(f"sensor.{DOMAIN}") assert state + + +async def test_already_setup(hass): + """Test we abort if already setup.""" + MockConfigEntry(domain=DOMAIN, data={},).add_to_hass(hass) + + # Should fail, same NAME + result = await hass.config_entries.flow.async_init( + DOMAIN, context={"source": SOURCE_USER} + ) + assert result["type"] == data_entry_flow.RESULT_TYPE_ABORT + assert result["reason"] == "single_instance_allowed" diff --git a/tests/components/local_ip/test_init.py b/tests/components/local_ip/test_init.py index fb43f06eea2..3f5c4395f2d 100644 --- a/tests/components/local_ip/test_init.py +++ b/tests/components/local_ip/test_init.py @@ -9,7 +9,7 @@ from homeassistant.util import get_local_ip @pytest.fixture(name="config") def config_fixture(): """Create hass config fixture.""" - return {DOMAIN: {"name": "test"}} + return {DOMAIN: {}} async def test_basic_setup(hass, config): @@ -17,6 +17,6 @@ async def test_basic_setup(hass, config): assert await async_setup_component(hass, DOMAIN, config) await hass.async_block_till_done() local_ip = await hass.async_add_executor_job(get_local_ip) - state = hass.states.get("sensor.test") + state = hass.states.get(f"sensor.{DOMAIN}") assert state assert state.state == local_ip