Add unique ID to Airly config entries (#30681)

* Add unique ID to Airly config entries

* Update tests

* Update tests

* Fix typo

* Remove unnecesary and undo changes in first test

* Suggested change
This commit is contained in:
Maciej Bieniek 2020-01-13 13:28:07 +01:00 committed by springstan
parent ce13fb8d73
commit 15645ab0c9
6 changed files with 43 additions and 43 deletions

View File

@ -41,6 +41,12 @@ async def async_setup_entry(hass, config_entry):
latitude = config_entry.data[CONF_LATITUDE] latitude = config_entry.data[CONF_LATITUDE]
longitude = config_entry.data[CONF_LONGITUDE] longitude = config_entry.data[CONF_LONGITUDE]
# For backwards compat, set unique ID
if config_entry.unique_id is None:
hass.config_entries.async_update_entry(
config_entry, unique_id=f"{latitude}-{longitude}"
)
websession = async_get_clientsession(hass) websession = async_get_clientsession(hass)
airly = AirlyData(websession, api_key, latitude, longitude) airly = AirlyData(websession, api_key, latitude, longitude)

View File

@ -5,7 +5,7 @@ from homeassistant.components.air_quality import (
ATTR_PM_10, ATTR_PM_10,
AirQualityEntity, AirQualityEntity,
) )
from homeassistant.const import CONF_LATITUDE, CONF_LONGITUDE, CONF_NAME from homeassistant.const import CONF_NAME
from .const import ( from .const import (
ATTR_API_ADVICE, ATTR_API_ADVICE,
@ -35,13 +35,10 @@ LABEL_PM_10_PERCENT = f"{ATTR_PM_10}_percent_of_limit"
async def async_setup_entry(hass, config_entry, async_add_entities): async def async_setup_entry(hass, config_entry, async_add_entities):
"""Set up Airly air_quality entity based on a config entry.""" """Set up Airly air_quality entity based on a config entry."""
name = config_entry.data[CONF_NAME] name = config_entry.data[CONF_NAME]
latitude = config_entry.data[CONF_LATITUDE]
longitude = config_entry.data[CONF_LONGITUDE]
unique_id = f"{latitude}-{longitude}"
data = hass.data[DOMAIN][DATA_CLIENT][config_entry.entry_id] data = hass.data[DOMAIN][DATA_CLIENT][config_entry.entry_id]
async_add_entities([AirlyAirQuality(data, name, unique_id)], True) async_add_entities([AirlyAirQuality(data, name, config_entry.unique_id)], True)
def round_state(func): def round_state(func):

View File

@ -6,19 +6,14 @@ import voluptuous as vol
from homeassistant import config_entries from homeassistant import config_entries
from homeassistant.const import CONF_API_KEY, CONF_LATITUDE, CONF_LONGITUDE, CONF_NAME from homeassistant.const import CONF_API_KEY, CONF_LATITUDE, CONF_LONGITUDE, CONF_NAME
from homeassistant.core import callback
from homeassistant.helpers.aiohttp_client import async_get_clientsession from homeassistant.helpers.aiohttp_client import async_get_clientsession
import homeassistant.helpers.config_validation as cv import homeassistant.helpers.config_validation as cv
from .const import DEFAULT_NAME, DOMAIN, NO_AIRLY_SENSORS from .const import ( # pylint:disable=unused-import
DEFAULT_NAME,
DOMAIN,
@callback NO_AIRLY_SENSORS,
def configured_instances(hass): )
"""Return a set of configured Airly instances."""
return set(
entry.data[CONF_NAME] for entry in hass.config_entries.async_entries(DOMAIN)
)
class AirlyFlowHandler(config_entries.ConfigFlow, domain=DOMAIN): class AirlyFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
@ -38,8 +33,10 @@ class AirlyFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
websession = async_get_clientsession(self.hass) websession = async_get_clientsession(self.hass)
if user_input is not None: if user_input is not None:
if user_input[CONF_NAME] in configured_instances(self.hass): await self.async_set_unique_id(
self._errors[CONF_NAME] = "name_exists" f"{user_input[CONF_LATITUDE]}-{user_input[CONF_LONGITUDE]}"
)
self._abort_if_unique_id_configured()
api_key_valid = await self._test_api_key(websession, user_input["api_key"]) api_key_valid = await self._test_api_key(websession, user_input["api_key"])
if not api_key_valid: if not api_key_valid:
self._errors["base"] = "auth" self._errors["base"] = "auth"

View File

@ -2,8 +2,6 @@
from homeassistant.const import ( from homeassistant.const import (
ATTR_ATTRIBUTION, ATTR_ATTRIBUTION,
ATTR_DEVICE_CLASS, ATTR_DEVICE_CLASS,
CONF_LATITUDE,
CONF_LONGITUDE,
CONF_NAME, CONF_NAME,
DEVICE_CLASS_HUMIDITY, DEVICE_CLASS_HUMIDITY,
DEVICE_CLASS_PRESSURE, DEVICE_CLASS_PRESSURE,
@ -62,14 +60,12 @@ SENSOR_TYPES = {
async def async_setup_entry(hass, config_entry, async_add_entities): async def async_setup_entry(hass, config_entry, async_add_entities):
"""Set up Airly sensor entities based on a config entry.""" """Set up Airly sensor entities based on a config entry."""
name = config_entry.data[CONF_NAME] name = config_entry.data[CONF_NAME]
latitude = config_entry.data[CONF_LATITUDE]
longitude = config_entry.data[CONF_LONGITUDE]
data = hass.data[DOMAIN][DATA_CLIENT][config_entry.entry_id] data = hass.data[DOMAIN][DATA_CLIENT][config_entry.entry_id]
sensors = [] sensors = []
for sensor in SENSOR_TYPES: for sensor in SENSOR_TYPES:
unique_id = f"{latitude}-{longitude}-{sensor.lower()}" unique_id = f"{config_entry.unique_id}-{sensor.lower()}"
sensors.append(AirlySensor(data, name, sensor, unique_id)) sensors.append(AirlySensor(data, name, sensor, unique_id))
async_add_entities(sensors, True) async_add_entities(sensors, True)

View File

@ -14,9 +14,11 @@
} }
}, },
"error": { "error": {
"name_exists": "Name already exists.",
"wrong_location": "No Airly measuring stations in this area.", "wrong_location": "No Airly measuring stations in this area.",
"auth": "API key is not correct." "auth": "API key is not correct."
},
"abort": {
"already_configured": "Airly integration for these coordinates is already configured."
} }
} }
} }

View File

@ -5,8 +5,8 @@ from airly.exceptions import AirlyError
from asynctest import patch from asynctest import patch
from homeassistant import data_entry_flow from homeassistant import data_entry_flow
from homeassistant.components.airly import config_flow
from homeassistant.components.airly.const import DOMAIN from homeassistant.components.airly.const import DOMAIN
from homeassistant.config_entries import SOURCE_USER
from homeassistant.const import CONF_API_KEY, CONF_LATITUDE, CONF_LONGITUDE, CONF_NAME from homeassistant.const import CONF_API_KEY, CONF_LATITUDE, CONF_LONGITUDE, CONF_NAME
from tests.common import MockConfigEntry, load_fixture from tests.common import MockConfigEntry, load_fixture
@ -21,13 +21,12 @@ CONFIG = {
async def test_show_form(hass): async def test_show_form(hass):
"""Test that the form is served with no input.""" """Test that the form is served with no input."""
flow = config_flow.AirlyFlowHandler() result = await hass.config_entries.flow.async_init(
flow.hass = hass DOMAIN, context={"source": SOURCE_USER}
)
result = await flow.async_step_user(user_input=None)
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
assert result["step_id"] == "user" assert result["step_id"] == SOURCE_USER
async def test_invalid_api_key(hass): async def test_invalid_api_key(hass):
@ -36,10 +35,10 @@ async def test_invalid_api_key(hass):
"airly._private._RequestsHandler.get", "airly._private._RequestsHandler.get",
side_effect=AirlyError(403, {"message": "Invalid authentication credentials"}), side_effect=AirlyError(403, {"message": "Invalid authentication credentials"}),
): ):
flow = config_flow.AirlyFlowHandler()
flow.hass = hass
result = await flow.async_step_user(user_input=CONFIG) result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": SOURCE_USER}, data=CONFIG
)
assert result["errors"] == {"base": "auth"} assert result["errors"] == {"base": "auth"}
@ -50,10 +49,10 @@ async def test_invalid_location(hass):
"airly._private._RequestsHandler.get", "airly._private._RequestsHandler.get",
return_value=json.loads(load_fixture("airly_no_station.json")), return_value=json.loads(load_fixture("airly_no_station.json")),
): ):
flow = config_flow.AirlyFlowHandler()
flow.hass = hass
result = await flow.async_step_user(user_input=CONFIG) result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": SOURCE_USER}, data=CONFIG
)
assert result["errors"] == {"base": "wrong_location"} assert result["errors"] == {"base": "wrong_location"}
@ -65,13 +64,16 @@ async def test_duplicate_error(hass):
"airly._private._RequestsHandler.get", "airly._private._RequestsHandler.get",
return_value=json.loads(load_fixture("airly_valid_station.json")), return_value=json.loads(load_fixture("airly_valid_station.json")),
): ):
MockConfigEntry(domain=DOMAIN, data=CONFIG).add_to_hass(hass) MockConfigEntry(domain=DOMAIN, unique_id="123-456", data=CONFIG).add_to_hass(
flow = config_flow.AirlyFlowHandler() hass
flow.hass = hass )
result = await flow.async_step_user(user_input=CONFIG) result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": SOURCE_USER}, data=CONFIG
)
assert result["errors"] == {CONF_NAME: "name_exists"} assert result["type"] == "abort"
assert result["reason"] == "already_configured"
async def test_create_entry(hass): async def test_create_entry(hass):
@ -81,10 +83,10 @@ async def test_create_entry(hass):
"airly._private._RequestsHandler.get", "airly._private._RequestsHandler.get",
return_value=json.loads(load_fixture("airly_valid_station.json")), return_value=json.loads(load_fixture("airly_valid_station.json")),
): ):
flow = config_flow.AirlyFlowHandler()
flow.hass = hass
result = await flow.async_step_user(user_input=CONFIG) result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": SOURCE_USER}, data=CONFIG
)
assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
assert result["title"] == CONFIG[CONF_NAME] assert result["title"] == CONFIG[CONF_NAME]