Add local_ip component (#29973)

* Added localip component

* Split config and core logic, and migrate to sensor platform (requested by @MartinHjelmare)
Also allow overriding the sensor name via the config

* Tweak docstring

Co-Authored-By: Fabian Affolter <mail@fabian-affolter.ch>

* Initial support for config entries

* Rename localip to local_ip (1/2)

* Rename localip to local_ip (2/2)

* Add test for config_flow

* Split and rename tests

* Remove unneeded code from config_flow

* Implement configuration as config entry import.  Other misc requested changes from code review.

* Fix tests

* minor code review fixes

* remove unneeded code

Co-authored-by: Fabian Affolter <mail@fabian-affolter.ch>
This commit is contained in:
Issac 2019-12-31 15:34:53 +02:00 committed by Martin Hjelmare
parent 5414e9d155
commit 3f570245aa
10 changed files with 179 additions and 0 deletions

View File

@ -187,6 +187,7 @@ homeassistant/components/life360/* @pnbruckner
homeassistant/components/linky/* @Quentame
homeassistant/components/linux_battery/* @fabaff
homeassistant/components/liveboxplaytv/* @pschmitt
homeassistant/components/local_ip/* @issacg
homeassistant/components/logger/* @home-assistant/core
homeassistant/components/logi_circle/* @evanjd
homeassistant/components/lovelace/* @home-assistant/frontend

View File

@ -0,0 +1,42 @@
"""Get the local IP address of the Home Assistant instance."""
import voluptuous as vol
from homeassistant import config_entries
from homeassistant.const import CONF_NAME
from homeassistant.core import HomeAssistant
import homeassistant.helpers.config_validation as cv
DOMAIN = "local_ip"
PLATFORM = "sensor"
CONFIG_SCHEMA = vol.Schema(
{DOMAIN: vol.Schema({vol.Optional(CONF_NAME, default=DOMAIN): cv.string})},
extra=vol.ALLOW_EXTRA,
)
async def async_setup(hass: HomeAssistant, config: dict):
"""Set up local_ip from configuration.yaml."""
conf = config.get(DOMAIN)
if conf:
hass.async_create_task(
hass.config_entries.flow.async_init(
DOMAIN, data=conf, context={"source": config_entries.SOURCE_IMPORT}
)
)
return True
async def async_setup_entry(hass: HomeAssistant, entry: config_entries.ConfigEntry):
"""Set up local_ip from a config entry."""
hass.async_create_task(
hass.config_entries.async_forward_entry_setup(entry, PLATFORM)
)
return True
async def async_unload_entry(hass: HomeAssistant, entry: config_entries.ConfigEntry):
"""Unload a config entry."""
return await hass.config_entries.async_forward_entry_unload(entry, PLATFORM)

View File

@ -0,0 +1,34 @@
"""Config flow for local_ip."""
import voluptuous as vol
from homeassistant import config_entries
from . import DOMAIN
class SimpleConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
"""Handle a config flow for local_ip."""
VERSION = 1
CONNECTION_CLASS = config_entries.CONN_CLASS_LOCAL_POLL
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)
return self.async_show_form(
step_id="user",
data_schema=vol.Schema({vol.Required("name", default=DOMAIN): str}),
errors={},
)
async def async_step_import(self, import_info):
"""Handle import from config file."""
return await self.async_step_user(import_info)

View File

@ -0,0 +1,9 @@
{
"domain": "local_ip",
"name": "Local IP Address",
"config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/local_ip",
"dependencies": [],
"codeowners": ["@issacg"],
"requirements": []
}

View File

@ -0,0 +1,34 @@
"""Sensor platform for local_ip."""
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity import Entity
from homeassistant.util import get_local_ip
async def async_setup_entry(hass: HomeAssistant, config_entry, async_add_entities):
"""Set up the platform from config_entry."""
name = config_entry.data["name"]
async_add_entities([IPSensor(name)], True)
class IPSensor(Entity):
"""A simple sensor."""
def __init__(self, name: str):
"""Initialize the sensor."""
self._state = None
self._name = name
@property
def name(self):
"""Return the name of the sensor."""
return self._name
@property
def state(self):
"""Return the state of the sensor."""
return self._state
def update(self):
"""Fetch new state data for the sensor."""
self._state = get_local_ip()

View File

@ -0,0 +1,16 @@
{
"config": {
"title": "Local IP Address",
"step": {
"user": {
"title": "Local IP Address",
"data": {
"name": "Sensor Name"
}
}
},
"abort": {
"already_configured": "Integration is already configured with an existing sensor with that name"
}
}
}

View File

@ -46,6 +46,7 @@ FLOWS = [
"life360",
"lifx",
"linky",
"local_ip",
"locative",
"logi_circle",
"luftdaten",

View File

@ -0,0 +1 @@
"""Tests for the local_ip integration."""

View File

@ -0,0 +1,19 @@
"""Tests for the local_ip config_flow."""
from homeassistant.components.local_ip import DOMAIN
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"}
)
assert result["type"] == "form"
result = await hass.config_entries.flow.async_configure(
result["flow_id"], {"name": "test"}
)
assert result["type"] == "create_entry"
await hass.async_block_till_done()
state = hass.states.get("sensor.test")
assert state

View File

@ -0,0 +1,22 @@
"""Tests for the local_ip component."""
import pytest
from homeassistant.components.local_ip import DOMAIN
from homeassistant.setup import async_setup_component
from homeassistant.util import get_local_ip
@pytest.fixture(name="config")
def config_fixture():
"""Create hass config fixture."""
return {DOMAIN: {"name": "test"}}
async def test_basic_setup(hass, config):
"""Test component setup creates entry from 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")
assert state
assert state.state == local_ip