mirror of
https://github.com/home-assistant/core.git
synced 2025-07-21 20:27:08 +00:00
Fix WUnderground duplicate entity ids (#13285)
* Fix WUnderground duplicate entity ids * Entity Namespace
This commit is contained in:
parent
f5093b474a
commit
3442b6741d
@ -14,11 +14,12 @@ import async_timeout
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.helpers.typing import HomeAssistantType, ConfigType
|
||||
from homeassistant.components import sensor
|
||||
from homeassistant.components.sensor import PLATFORM_SCHEMA, ENTITY_ID_FORMAT
|
||||
from homeassistant.const import (
|
||||
CONF_MONITORED_CONDITIONS, CONF_API_KEY, CONF_LATITUDE, CONF_LONGITUDE,
|
||||
TEMP_FAHRENHEIT, TEMP_CELSIUS, LENGTH_INCHES, LENGTH_KILOMETERS,
|
||||
LENGTH_MILES, LENGTH_FEET, ATTR_ATTRIBUTION)
|
||||
LENGTH_MILES, LENGTH_FEET, ATTR_ATTRIBUTION, CONF_ENTITY_NAMESPACE)
|
||||
from homeassistant.exceptions import PlatformNotReady
|
||||
from homeassistant.helpers.entity import Entity, async_generate_entity_id
|
||||
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
||||
@ -617,6 +618,8 @@ LANG_CODES = [
|
||||
'CY', 'SN', 'JI', 'YI',
|
||||
]
|
||||
|
||||
DEFAULT_ENTITY_NAMESPACE = 'pws'
|
||||
|
||||
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
|
||||
vol.Required(CONF_API_KEY): cv.string,
|
||||
vol.Optional(CONF_PWS_ID): cv.string,
|
||||
@ -627,22 +630,31 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
|
||||
'Latitude and longitude must exist together'): cv.longitude,
|
||||
vol.Required(CONF_MONITORED_CONDITIONS):
|
||||
vol.All(cv.ensure_list, vol.Length(min=1), [vol.In(SENSOR_TYPES)]),
|
||||
vol.Optional(CONF_ENTITY_NAMESPACE,
|
||||
default=DEFAULT_ENTITY_NAMESPACE): cv.string,
|
||||
})
|
||||
|
||||
# Stores a list of entity ids we added in order to support multiple stations
|
||||
# at once.
|
||||
ADDED_ENTITY_IDS_KEY = 'wunderground_added_entity_ids'
|
||||
|
||||
|
||||
@asyncio.coroutine
|
||||
def async_setup_platform(hass: HomeAssistantType, config: ConfigType,
|
||||
async_add_devices, discovery_info=None):
|
||||
"""Set up the WUnderground sensor."""
|
||||
hass.data.setdefault(ADDED_ENTITY_IDS_KEY, set())
|
||||
|
||||
latitude = config.get(CONF_LATITUDE, hass.config.latitude)
|
||||
longitude = config.get(CONF_LONGITUDE, hass.config.longitude)
|
||||
namespace = config.get(CONF_ENTITY_NAMESPACE)
|
||||
|
||||
rest = WUndergroundData(
|
||||
hass, config.get(CONF_API_KEY), config.get(CONF_PWS_ID),
|
||||
config.get(CONF_LANG), latitude, longitude)
|
||||
sensors = []
|
||||
for variable in config[CONF_MONITORED_CONDITIONS]:
|
||||
sensors.append(WUndergroundSensor(hass, rest, variable))
|
||||
sensors.append(WUndergroundSensor(hass, rest, variable, namespace))
|
||||
|
||||
yield from rest.async_update()
|
||||
if not rest.data:
|
||||
@ -654,7 +666,8 @@ def async_setup_platform(hass: HomeAssistantType, config: ConfigType,
|
||||
class WUndergroundSensor(Entity):
|
||||
"""Implementing the WUnderground sensor."""
|
||||
|
||||
def __init__(self, hass: HomeAssistantType, rest, condition):
|
||||
def __init__(self, hass: HomeAssistantType, rest, condition,
|
||||
namespace: str):
|
||||
"""Initialize the sensor."""
|
||||
self.rest = rest
|
||||
self._condition = condition
|
||||
@ -666,8 +679,12 @@ class WUndergroundSensor(Entity):
|
||||
self._entity_picture = None
|
||||
self._unit_of_measurement = self._cfg_expand("unit_of_measurement")
|
||||
self.rest.request_feature(SENSOR_TYPES[condition].feature)
|
||||
current_ids = set(hass.states.async_entity_ids(sensor.DOMAIN))
|
||||
current_ids |= hass.data[ADDED_ENTITY_IDS_KEY]
|
||||
self.entity_id = async_generate_entity_id(
|
||||
ENTITY_ID_FORMAT, "pws_" + condition, hass=hass)
|
||||
ENTITY_ID_FORMAT, "{} {}".format(namespace, condition),
|
||||
current_ids=current_ids)
|
||||
hass.data[ADDED_ENTITY_IDS_KEY].add(self.entity_id)
|
||||
|
||||
def _cfg_expand(self, what, default=None):
|
||||
"""Parse and return sensor data."""
|
||||
|
@ -4,7 +4,7 @@ import logging
|
||||
import functools as ft
|
||||
from timeit import default_timer as timer
|
||||
|
||||
from typing import Optional, List
|
||||
from typing import Optional, List, Iterable
|
||||
|
||||
from homeassistant.const import (
|
||||
ATTR_ASSUMED_STATE, ATTR_FRIENDLY_NAME, ATTR_HIDDEN, ATTR_ICON,
|
||||
@ -42,7 +42,7 @@ def generate_entity_id(entity_id_format: str, name: Optional[str],
|
||||
|
||||
@callback
|
||||
def async_generate_entity_id(entity_id_format: str, name: Optional[str],
|
||||
current_ids: Optional[List[str]] = None,
|
||||
current_ids: Optional[Iterable[str]] = None,
|
||||
hass: Optional[HomeAssistant] = None) -> str:
|
||||
"""Generate a unique entity ID based on given entity IDs or used IDs."""
|
||||
if current_ids is None:
|
||||
|
@ -13,7 +13,7 @@ from functools import wraps
|
||||
from types import MappingProxyType
|
||||
from unicodedata import normalize
|
||||
|
||||
from typing import Any, Optional, TypeVar, Callable, Sequence, KeysView, Union
|
||||
from typing import Any, Optional, TypeVar, Callable, KeysView, Union, Iterable
|
||||
|
||||
from .dt import as_local, utcnow
|
||||
|
||||
@ -72,7 +72,7 @@ def convert(value: T, to_type: Callable[[T], U],
|
||||
|
||||
|
||||
def ensure_unique_string(preferred_string: str, current_strings:
|
||||
Union[Sequence[str], KeysView[str]]) -> str:
|
||||
Union[Iterable[str], KeysView[str]]) -> str:
|
||||
"""Return a string that is not present in current_strings.
|
||||
|
||||
If preferred string exists will append _2, _3, ..
|
||||
|
@ -143,3 +143,23 @@ def test_invalid_data(hass, aioclient_mock):
|
||||
for condition in VALID_CONFIG['monitored_conditions']:
|
||||
state = hass.states.get('sensor.pws_' + condition)
|
||||
assert state.state == STATE_UNKNOWN
|
||||
|
||||
|
||||
async def test_entity_id_with_multiple_stations(hass, aioclient_mock):
|
||||
"""Test not generating duplicate entity ids with multiple stations."""
|
||||
aioclient_mock.get(URL, text=load_fixture('wunderground-valid.json'))
|
||||
|
||||
config = [
|
||||
VALID_CONFIG,
|
||||
{**VALID_CONFIG, 'entity_namespace': 'hi'}
|
||||
]
|
||||
await async_setup_component(hass, 'sensor', {'sensor': config})
|
||||
await hass.async_block_till_done()
|
||||
|
||||
state = hass.states.get('sensor.pws_weather')
|
||||
assert state is not None
|
||||
assert state.state == 'Clear'
|
||||
|
||||
state = hass.states.get('sensor.hi_weather')
|
||||
assert state is not None
|
||||
assert state.state == 'Clear'
|
||||
|
Loading…
x
Reference in New Issue
Block a user