mirror of
https://github.com/home-assistant/core.git
synced 2025-07-19 11:17:21 +00:00
WUnderground unique ids (#13311)
* WUnderground unique_id * Remove async_generate_entity_id * Lint * Address comment
This commit is contained in:
parent
ce98dfe395
commit
14c7fa8882
@ -15,13 +15,13 @@ import voluptuous as vol
|
|||||||
|
|
||||||
from homeassistant.helpers.typing import HomeAssistantType, ConfigType
|
from homeassistant.helpers.typing import HomeAssistantType, ConfigType
|
||||||
from homeassistant.components import sensor
|
from homeassistant.components import sensor
|
||||||
from homeassistant.components.sensor import PLATFORM_SCHEMA, ENTITY_ID_FORMAT
|
from homeassistant.components.sensor import PLATFORM_SCHEMA
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
CONF_MONITORED_CONDITIONS, CONF_API_KEY, CONF_LATITUDE, CONF_LONGITUDE,
|
CONF_MONITORED_CONDITIONS, CONF_API_KEY, CONF_LATITUDE, CONF_LONGITUDE,
|
||||||
TEMP_FAHRENHEIT, TEMP_CELSIUS, LENGTH_INCHES, LENGTH_KILOMETERS,
|
TEMP_FAHRENHEIT, TEMP_CELSIUS, LENGTH_INCHES, LENGTH_KILOMETERS,
|
||||||
LENGTH_MILES, LENGTH_FEET, ATTR_ATTRIBUTION, CONF_ENTITY_NAMESPACE)
|
LENGTH_MILES, LENGTH_FEET, ATTR_ATTRIBUTION)
|
||||||
from homeassistant.exceptions import PlatformNotReady
|
from homeassistant.exceptions import PlatformNotReady
|
||||||
from homeassistant.helpers.entity import Entity, async_generate_entity_id
|
from homeassistant.helpers.entity import Entity
|
||||||
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
||||||
from homeassistant.util import Throttle
|
from homeassistant.util import Throttle
|
||||||
import homeassistant.helpers.config_validation as cv
|
import homeassistant.helpers.config_validation as cv
|
||||||
@ -618,8 +618,6 @@ LANG_CODES = [
|
|||||||
'CY', 'SN', 'JI', 'YI',
|
'CY', 'SN', 'JI', 'YI',
|
||||||
]
|
]
|
||||||
|
|
||||||
DEFAULT_ENTITY_NAMESPACE = 'pws'
|
|
||||||
|
|
||||||
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
|
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
|
||||||
vol.Required(CONF_API_KEY): cv.string,
|
vol.Required(CONF_API_KEY): cv.string,
|
||||||
vol.Optional(CONF_PWS_ID): cv.string,
|
vol.Optional(CONF_PWS_ID): cv.string,
|
||||||
@ -629,31 +627,30 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
|
|||||||
vol.Inclusive(CONF_LONGITUDE, 'coordinates',
|
vol.Inclusive(CONF_LONGITUDE, 'coordinates',
|
||||||
'Latitude and longitude must exist together'): cv.longitude,
|
'Latitude and longitude must exist together'): cv.longitude,
|
||||||
vol.Required(CONF_MONITORED_CONDITIONS):
|
vol.Required(CONF_MONITORED_CONDITIONS):
|
||||||
vol.All(cv.ensure_list, vol.Length(min=1), [vol.In(SENSOR_TYPES)]),
|
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'
|
|
||||||
|
|
||||||
|
|
||||||
async def async_setup_platform(hass: HomeAssistantType, config: ConfigType,
|
async def async_setup_platform(hass: HomeAssistantType, config: ConfigType,
|
||||||
async_add_devices, discovery_info=None):
|
async_add_devices, discovery_info=None):
|
||||||
"""Set up the WUnderground sensor."""
|
"""Set up the WUnderground sensor."""
|
||||||
hass.data.setdefault(ADDED_ENTITY_IDS_KEY, set())
|
|
||||||
|
|
||||||
latitude = config.get(CONF_LATITUDE, hass.config.latitude)
|
latitude = config.get(CONF_LATITUDE, hass.config.latitude)
|
||||||
longitude = config.get(CONF_LONGITUDE, hass.config.longitude)
|
longitude = config.get(CONF_LONGITUDE, hass.config.longitude)
|
||||||
namespace = config.get(CONF_ENTITY_NAMESPACE)
|
pws_id = config.get(CONF_PWS_ID)
|
||||||
|
|
||||||
rest = WUndergroundData(
|
rest = WUndergroundData(
|
||||||
hass, config.get(CONF_API_KEY), config.get(CONF_PWS_ID),
|
hass, config.get(CONF_API_KEY), pws_id,
|
||||||
config.get(CONF_LANG), latitude, longitude)
|
config.get(CONF_LANG), latitude, longitude)
|
||||||
|
|
||||||
|
if pws_id is None:
|
||||||
|
unique_id_base = "@{:06f},{:06f}".format(longitude, latitude)
|
||||||
|
else:
|
||||||
|
# Manually specified weather station, use that for unique_id
|
||||||
|
unique_id_base = pws_id
|
||||||
sensors = []
|
sensors = []
|
||||||
for variable in config[CONF_MONITORED_CONDITIONS]:
|
for variable in config[CONF_MONITORED_CONDITIONS]:
|
||||||
sensors.append(WUndergroundSensor(hass, rest, variable, namespace))
|
sensors.append(WUndergroundSensor(hass, rest, variable,
|
||||||
|
unique_id_base))
|
||||||
|
|
||||||
await rest.async_update()
|
await rest.async_update()
|
||||||
if not rest.data:
|
if not rest.data:
|
||||||
@ -666,7 +663,7 @@ class WUndergroundSensor(Entity):
|
|||||||
"""Implementing the WUnderground sensor."""
|
"""Implementing the WUnderground sensor."""
|
||||||
|
|
||||||
def __init__(self, hass: HomeAssistantType, rest, condition,
|
def __init__(self, hass: HomeAssistantType, rest, condition,
|
||||||
namespace: str):
|
unique_id_base: str):
|
||||||
"""Initialize the sensor."""
|
"""Initialize the sensor."""
|
||||||
self.rest = rest
|
self.rest = rest
|
||||||
self._condition = condition
|
self._condition = condition
|
||||||
@ -678,12 +675,10 @@ class WUndergroundSensor(Entity):
|
|||||||
self._entity_picture = None
|
self._entity_picture = None
|
||||||
self._unit_of_measurement = self._cfg_expand("unit_of_measurement")
|
self._unit_of_measurement = self._cfg_expand("unit_of_measurement")
|
||||||
self.rest.request_feature(SENSOR_TYPES[condition].feature)
|
self.rest.request_feature(SENSOR_TYPES[condition].feature)
|
||||||
current_ids = set(hass.states.async_entity_ids(sensor.DOMAIN))
|
# This is only the suggested entity id, it might get changed by
|
||||||
current_ids |= hass.data[ADDED_ENTITY_IDS_KEY]
|
# the entity registry later.
|
||||||
self.entity_id = async_generate_entity_id(
|
self.entity_id = sensor.ENTITY_ID_FORMAT.format('pws_' + condition)
|
||||||
ENTITY_ID_FORMAT, "{} {}".format(namespace, condition),
|
self._unique_id = "{},{}".format(unique_id_base, condition)
|
||||||
current_ids=current_ids)
|
|
||||||
hass.data[ADDED_ENTITY_IDS_KEY].add(self.entity_id)
|
|
||||||
|
|
||||||
def _cfg_expand(self, what, default=None):
|
def _cfg_expand(self, what, default=None):
|
||||||
"""Parse and return sensor data."""
|
"""Parse and return sensor data."""
|
||||||
@ -763,6 +758,11 @@ class WUndergroundSensor(Entity):
|
|||||||
self._entity_picture = re.sub(r'^http://', 'https://',
|
self._entity_picture = re.sub(r'^http://', 'https://',
|
||||||
url, flags=re.IGNORECASE)
|
url, flags=re.IGNORECASE)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def unique_id(self) -> str:
|
||||||
|
"""Return a unique ID."""
|
||||||
|
return self._unique_id
|
||||||
|
|
||||||
|
|
||||||
class WUndergroundData(object):
|
class WUndergroundData(object):
|
||||||
"""Get data from WUnderground."""
|
"""Get data from WUnderground."""
|
||||||
|
@ -148,10 +148,11 @@ def test_invalid_data(hass, aioclient_mock):
|
|||||||
async def test_entity_id_with_multiple_stations(hass, aioclient_mock):
|
async def test_entity_id_with_multiple_stations(hass, aioclient_mock):
|
||||||
"""Test not generating duplicate entity ids with multiple stations."""
|
"""Test not generating duplicate entity ids with multiple stations."""
|
||||||
aioclient_mock.get(URL, text=load_fixture('wunderground-valid.json'))
|
aioclient_mock.get(URL, text=load_fixture('wunderground-valid.json'))
|
||||||
|
aioclient_mock.get(PWS_URL, text=load_fixture('wunderground-valid.json'))
|
||||||
|
|
||||||
config = [
|
config = [
|
||||||
VALID_CONFIG,
|
VALID_CONFIG,
|
||||||
{**VALID_CONFIG, 'entity_namespace': 'hi'}
|
{**VALID_CONFIG_PWS, 'entity_namespace': 'hi'}
|
||||||
]
|
]
|
||||||
await async_setup_component(hass, 'sensor', {'sensor': config})
|
await async_setup_component(hass, 'sensor', {'sensor': config})
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
@ -160,6 +161,25 @@ async def test_entity_id_with_multiple_stations(hass, aioclient_mock):
|
|||||||
assert state is not None
|
assert state is not None
|
||||||
assert state.state == 'Clear'
|
assert state.state == 'Clear'
|
||||||
|
|
||||||
state = hass.states.get('sensor.hi_weather')
|
state = hass.states.get('sensor.hi_pws_weather')
|
||||||
assert state is not None
|
assert state is not None
|
||||||
assert state.state == 'Clear'
|
assert state.state == 'Clear'
|
||||||
|
|
||||||
|
|
||||||
|
async def test_fails_because_of_unique_id(hass, aioclient_mock):
|
||||||
|
"""Test same config twice fails because of unique_id."""
|
||||||
|
aioclient_mock.get(URL, text=load_fixture('wunderground-valid.json'))
|
||||||
|
aioclient_mock.get(PWS_URL, text=load_fixture('wunderground-valid.json'))
|
||||||
|
|
||||||
|
config = [
|
||||||
|
VALID_CONFIG,
|
||||||
|
{**VALID_CONFIG, 'entity_namespace': 'hi'},
|
||||||
|
VALID_CONFIG_PWS
|
||||||
|
]
|
||||||
|
await async_setup_component(hass, 'sensor', {'sensor': config})
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
states = hass.states.async_all()
|
||||||
|
expected = len(VALID_CONFIG['monitored_conditions']) + \
|
||||||
|
len(VALID_CONFIG_PWS['monitored_conditions'])
|
||||||
|
assert len(states) == expected
|
||||||
|
Loading…
x
Reference in New Issue
Block a user