Move attribution attribute to Entity base class (#57492)
parent
d10b1d9fe0
commit
13db867c1d
|
@ -5,7 +5,7 @@ from typing import Any, cast
|
|||
|
||||
from homeassistant.components.sensor import SensorEntity
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import ATTR_ATTRIBUTION, CONF_NAME, DEVICE_CLASS_TEMPERATURE
|
||||
from homeassistant.const import CONF_NAME, DEVICE_CLASS_TEMPERATURE
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.typing import StateType
|
||||
|
@ -59,6 +59,7 @@ async def async_setup_entry(
|
|||
class AccuWeatherSensor(CoordinatorEntity, SensorEntity):
|
||||
"""Define an AccuWeather entity."""
|
||||
|
||||
_attr_attribution = ATTRIBUTION
|
||||
coordinator: AccuWeatherDataUpdateCoordinator
|
||||
entity_description: AccuWeatherSensorDescription
|
||||
|
||||
|
@ -75,7 +76,7 @@ class AccuWeatherSensor(CoordinatorEntity, SensorEntity):
|
|||
self._sensor_data = _get_sensor_data(
|
||||
coordinator.data, forecast_day, description.key
|
||||
)
|
||||
self._attrs = {ATTR_ATTRIBUTION: ATTRIBUTION}
|
||||
self._attrs: dict[str, Any] = {}
|
||||
if forecast_day is not None:
|
||||
self._attr_name = f"{name} {description.name} {forecast_day}d"
|
||||
self._attr_unique_id = (
|
||||
|
|
|
@ -6,10 +6,7 @@ import logging
|
|||
from typing import Final, final
|
||||
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import (
|
||||
ATTR_ATTRIBUTION,
|
||||
CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
)
|
||||
from homeassistant.const import CONCENTRATION_MICROGRAMS_PER_CUBIC_METER
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.config_validation import ( # noqa: F401
|
||||
PLATFORM_SCHEMA,
|
||||
|
@ -41,7 +38,6 @@ SCAN_INTERVAL: Final = timedelta(seconds=30)
|
|||
|
||||
PROP_TO_ATTR: Final[dict[str, str]] = {
|
||||
"air_quality_index": ATTR_AQI,
|
||||
"attribution": ATTR_ATTRIBUTION,
|
||||
"carbon_dioxide": ATTR_CO2,
|
||||
"carbon_monoxide": ATTR_CO,
|
||||
"nitrogen_oxide": ATTR_N2O,
|
||||
|
@ -114,11 +110,6 @@ class AirQualityEntity(Entity):
|
|||
"""Return the CO2 (carbon dioxide) level."""
|
||||
return None
|
||||
|
||||
@property
|
||||
def attribution(self) -> StateType:
|
||||
"""Return the attribution."""
|
||||
return None
|
||||
|
||||
@property
|
||||
def sulphur_dioxide(self) -> StateType:
|
||||
"""Return the SO2 (sulphur dioxide) level."""
|
||||
|
|
|
@ -18,7 +18,6 @@ from homeassistant.components.weather import (
|
|||
ATTR_FORECAST_TIME,
|
||||
ATTR_FORECAST_WIND_BEARING,
|
||||
ATTR_FORECAST_WIND_SPEED,
|
||||
ATTR_WEATHER_ATTRIBUTION,
|
||||
ATTR_WEATHER_HUMIDITY,
|
||||
ATTR_WEATHER_PRESSURE,
|
||||
ATTR_WEATHER_TEMPERATURE,
|
||||
|
@ -184,7 +183,6 @@ FORECAST_MAP = {
|
|||
}
|
||||
|
||||
ATTR_MAP = {
|
||||
ATTR_WEATHER_ATTRIBUTION: "attribution",
|
||||
ATTR_WEATHER_HUMIDITY: "humidity",
|
||||
ATTR_WEATHER_PRESSURE: "pressure",
|
||||
ATTR_WEATHER_TEMPERATURE: "temperature",
|
||||
|
|
|
@ -47,7 +47,6 @@ ATTR_FORECAST_TEMP_LOW: Final = "templow"
|
|||
ATTR_FORECAST_TIME: Final = "datetime"
|
||||
ATTR_FORECAST_WIND_BEARING: Final = "wind_bearing"
|
||||
ATTR_FORECAST_WIND_SPEED: Final = "wind_speed"
|
||||
ATTR_WEATHER_ATTRIBUTION = "attribution"
|
||||
ATTR_WEATHER_HUMIDITY = "humidity"
|
||||
ATTR_WEATHER_OZONE = "ozone"
|
||||
ATTR_WEATHER_PRESSURE = "pressure"
|
||||
|
@ -107,7 +106,6 @@ class WeatherEntity(Entity):
|
|||
"""ABC for weather data."""
|
||||
|
||||
entity_description: WeatherEntityDescription
|
||||
_attr_attribution: str | None = None
|
||||
_attr_condition: str | None
|
||||
_attr_forecast: list[Forecast] | None = None
|
||||
_attr_humidity: float | None = None
|
||||
|
@ -156,11 +154,6 @@ class WeatherEntity(Entity):
|
|||
"""Return the ozone level."""
|
||||
return self._attr_ozone
|
||||
|
||||
@property
|
||||
def attribution(self) -> str | None:
|
||||
"""Return the attribution."""
|
||||
return self._attr_attribution
|
||||
|
||||
@property
|
||||
def visibility(self) -> float | None:
|
||||
"""Return the visibility."""
|
||||
|
@ -216,10 +209,6 @@ class WeatherEntity(Entity):
|
|||
if visibility is not None:
|
||||
data[ATTR_WEATHER_VISIBILITY] = visibility
|
||||
|
||||
attribution = self.attribution
|
||||
if attribution is not None:
|
||||
data[ATTR_WEATHER_ATTRIBUTION] = attribution
|
||||
|
||||
if self.forecast is not None:
|
||||
forecast = []
|
||||
for forecast_entry in self.forecast:
|
||||
|
|
|
@ -16,6 +16,7 @@ from typing import Any, TypedDict, final
|
|||
from homeassistant.config import DATA_CUSTOMIZE
|
||||
from homeassistant.const import (
|
||||
ATTR_ASSUMED_STATE,
|
||||
ATTR_ATTRIBUTION,
|
||||
ATTR_DEVICE_CLASS,
|
||||
ATTR_ENTITY_PICTURE,
|
||||
ATTR_FRIENDLY_NAME,
|
||||
|
@ -232,6 +233,7 @@ class Entity(ABC):
|
|||
|
||||
# Entity Properties
|
||||
_attr_assumed_state: bool = False
|
||||
_attr_attribution: str | None = None
|
||||
_attr_available: bool = True
|
||||
_attr_context_recent_time: timedelta = timedelta(seconds=5)
|
||||
_attr_device_class: str | None
|
||||
|
@ -397,6 +399,11 @@ class Entity(ABC):
|
|||
return self.entity_description.entity_registry_enabled_default
|
||||
return True
|
||||
|
||||
@property
|
||||
def attribution(self) -> str | None:
|
||||
"""Return the attribution."""
|
||||
return self._attr_attribution
|
||||
|
||||
# DO NOT OVERWRITE
|
||||
# These properties and methods are either managed by Home Assistant or they
|
||||
# are used to perform a very specific function. Overwriting these may
|
||||
|
@ -520,6 +527,9 @@ class Entity(ABC):
|
|||
if (device_class := self.device_class) is not None:
|
||||
attr[ATTR_DEVICE_CLASS] = str(device_class)
|
||||
|
||||
if (attribution := self.attribution) is not None:
|
||||
attr[ATTR_ATTRIBUTION] = attribution
|
||||
|
||||
end = timer()
|
||||
|
||||
if end - start > 0.4 and not self._slow_reported:
|
||||
|
|
|
@ -1,11 +1,7 @@
|
|||
"""The tests for the Air Quality component."""
|
||||
from homeassistant.components.air_quality import (
|
||||
ATTR_ATTRIBUTION,
|
||||
ATTR_N2O,
|
||||
ATTR_OZONE,
|
||||
ATTR_PM_10,
|
||||
)
|
||||
from homeassistant.components.air_quality import ATTR_N2O, ATTR_OZONE, ATTR_PM_10
|
||||
from homeassistant.const import (
|
||||
ATTR_ATTRIBUTION,
|
||||
ATTR_UNIT_OF_MEASUREMENT,
|
||||
CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
)
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
"""Tests for HomematicIP Cloud weather."""
|
||||
from homeassistant.components.homematicip_cloud import DOMAIN as HMIPC_DOMAIN
|
||||
from homeassistant.components.weather import (
|
||||
ATTR_WEATHER_ATTRIBUTION,
|
||||
ATTR_WEATHER_HUMIDITY,
|
||||
ATTR_WEATHER_TEMPERATURE,
|
||||
ATTR_WEATHER_WIND_BEARING,
|
||||
ATTR_WEATHER_WIND_SPEED,
|
||||
DOMAIN as WEATHER_DOMAIN,
|
||||
)
|
||||
from homeassistant.const import ATTR_ATTRIBUTION
|
||||
from homeassistant.setup import async_setup_component
|
||||
|
||||
from .helper import async_manipulate_test_data, get_and_check_entity_basics
|
||||
|
@ -38,7 +38,7 @@ async def test_hmip_weather_sensor(hass, default_mock_hap_factory):
|
|||
assert ha_state.attributes[ATTR_WEATHER_TEMPERATURE] == 4.3
|
||||
assert ha_state.attributes[ATTR_WEATHER_HUMIDITY] == 97
|
||||
assert ha_state.attributes[ATTR_WEATHER_WIND_SPEED] == 15.0
|
||||
assert ha_state.attributes[ATTR_WEATHER_ATTRIBUTION] == "Powered by Homematic IP"
|
||||
assert ha_state.attributes[ATTR_ATTRIBUTION] == "Powered by Homematic IP"
|
||||
|
||||
await async_manipulate_test_data(hass, hmip_device, "actualTemperature", 12.1)
|
||||
ha_state = hass.states.get(entity_id)
|
||||
|
@ -63,7 +63,7 @@ async def test_hmip_weather_sensor_pro(hass, default_mock_hap_factory):
|
|||
assert ha_state.attributes[ATTR_WEATHER_HUMIDITY] == 65
|
||||
assert ha_state.attributes[ATTR_WEATHER_WIND_SPEED] == 2.6
|
||||
assert ha_state.attributes[ATTR_WEATHER_WIND_BEARING] == 295.0
|
||||
assert ha_state.attributes[ATTR_WEATHER_ATTRIBUTION] == "Powered by Homematic IP"
|
||||
assert ha_state.attributes[ATTR_ATTRIBUTION] == "Powered by Homematic IP"
|
||||
|
||||
await async_manipulate_test_data(hass, hmip_device, "actualTemperature", 12.1)
|
||||
ha_state = hass.states.get(entity_id)
|
||||
|
@ -86,7 +86,7 @@ async def test_hmip_home_weather(hass, default_mock_hap_factory):
|
|||
assert ha_state.attributes[ATTR_WEATHER_HUMIDITY] == 54
|
||||
assert ha_state.attributes[ATTR_WEATHER_WIND_SPEED] == 8.6
|
||||
assert ha_state.attributes[ATTR_WEATHER_WIND_BEARING] == 294
|
||||
assert ha_state.attributes[ATTR_WEATHER_ATTRIBUTION] == "Powered by Homematic IP"
|
||||
assert ha_state.attributes[ATTR_ATTRIBUTION] == "Powered by Homematic IP"
|
||||
|
||||
await async_manipulate_test_data(
|
||||
hass, mock_hap.home.weather, "temperature", 28.3, fire_device=mock_hap.home
|
||||
|
|
|
@ -19,7 +19,6 @@ from homeassistant.components.weather import (
|
|||
ATTR_FORECAST_TEMP,
|
||||
ATTR_FORECAST_TEMP_LOW,
|
||||
ATTR_FORECAST_TIME,
|
||||
ATTR_WEATHER_ATTRIBUTION,
|
||||
ATTR_WEATHER_HUMIDITY,
|
||||
ATTR_WEATHER_PRESSURE,
|
||||
ATTR_WEATHER_TEMPERATURE,
|
||||
|
@ -27,7 +26,7 @@ from homeassistant.components.weather import (
|
|||
ATTR_WEATHER_WIND_BEARING,
|
||||
ATTR_WEATHER_WIND_SPEED,
|
||||
)
|
||||
from homeassistant.const import STATE_UNKNOWN
|
||||
from homeassistant.const import ATTR_ATTRIBUTION, STATE_UNKNOWN
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.util.dt import utcnow
|
||||
|
||||
|
@ -60,7 +59,7 @@ async def test_setup_hass(
|
|||
assert state.attributes[ATTR_SMHI_CLOUDINESS] == 50
|
||||
assert state.attributes[ATTR_SMHI_THUNDER_PROBABILITY] == 33
|
||||
assert state.attributes[ATTR_SMHI_WIND_GUST_SPEED] == 17
|
||||
assert state.attributes[ATTR_WEATHER_ATTRIBUTION].find("SMHI") >= 0
|
||||
assert state.attributes[ATTR_ATTRIBUTION].find("SMHI") >= 0
|
||||
assert state.attributes[ATTR_WEATHER_HUMIDITY] == 55
|
||||
assert state.attributes[ATTR_WEATHER_PRESSURE] == 1024
|
||||
assert state.attributes[ATTR_WEATHER_TEMPERATURE] == 17
|
||||
|
@ -94,9 +93,7 @@ async def test_properties_no_data(hass: HomeAssistant) -> None:
|
|||
assert state
|
||||
assert state.name == "test"
|
||||
assert state.state == STATE_UNKNOWN
|
||||
assert (
|
||||
state.attributes[ATTR_WEATHER_ATTRIBUTION] == "Swedish weather institute (SMHI)"
|
||||
)
|
||||
assert state.attributes[ATTR_ATTRIBUTION] == "Swedish weather institute (SMHI)"
|
||||
assert ATTR_WEATHER_HUMIDITY not in state.attributes
|
||||
assert ATTR_WEATHER_PRESSURE not in state.attributes
|
||||
assert ATTR_WEATHER_TEMPERATURE not in state.attributes
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
import pytest
|
||||
|
||||
from homeassistant.components.weather import (
|
||||
ATTR_WEATHER_ATTRIBUTION,
|
||||
ATTR_WEATHER_HUMIDITY,
|
||||
ATTR_WEATHER_OZONE,
|
||||
ATTR_WEATHER_PRESSURE,
|
||||
|
@ -12,6 +11,7 @@ from homeassistant.components.weather import (
|
|||
ATTR_WEATHER_WIND_SPEED,
|
||||
DOMAIN,
|
||||
)
|
||||
from homeassistant.const import ATTR_ATTRIBUTION
|
||||
|
||||
|
||||
@pytest.mark.parametrize("count,domain", [(1, DOMAIN)])
|
||||
|
@ -44,7 +44,7 @@ async def test_template_state_text(hass, start_ha):
|
|||
for attr, v_attr, value in [
|
||||
(
|
||||
"sensor.attribution",
|
||||
ATTR_WEATHER_ATTRIBUTION,
|
||||
ATTR_ATTRIBUTION,
|
||||
"The custom attribution",
|
||||
),
|
||||
("sensor.temperature", ATTR_WEATHER_TEMPERATURE, 22.3),
|
||||
|
|
|
@ -7,7 +7,6 @@ from homeassistant.components.weather import (
|
|||
ATTR_FORECAST_PRECIPITATION_PROBABILITY,
|
||||
ATTR_FORECAST_TEMP,
|
||||
ATTR_FORECAST_TEMP_LOW,
|
||||
ATTR_WEATHER_ATTRIBUTION,
|
||||
ATTR_WEATHER_HUMIDITY,
|
||||
ATTR_WEATHER_OZONE,
|
||||
ATTR_WEATHER_PRESSURE,
|
||||
|
@ -15,6 +14,7 @@ from homeassistant.components.weather import (
|
|||
ATTR_WEATHER_WIND_BEARING,
|
||||
ATTR_WEATHER_WIND_SPEED,
|
||||
)
|
||||
from homeassistant.const import ATTR_ATTRIBUTION
|
||||
from homeassistant.setup import async_setup_component
|
||||
from homeassistant.util.unit_system import METRIC_SYSTEM
|
||||
|
||||
|
@ -39,7 +39,7 @@ async def test_attributes(hass):
|
|||
assert data.get(ATTR_WEATHER_WIND_SPEED) == 0.5
|
||||
assert data.get(ATTR_WEATHER_WIND_BEARING) is None
|
||||
assert data.get(ATTR_WEATHER_OZONE) is None
|
||||
assert data.get(ATTR_WEATHER_ATTRIBUTION) == "Powered by Home Assistant"
|
||||
assert data.get(ATTR_ATTRIBUTION) == "Powered by Home Assistant"
|
||||
assert data.get(ATTR_FORECAST)[0].get(ATTR_FORECAST_CONDITION) == "rainy"
|
||||
assert data.get(ATTR_FORECAST)[0].get(ATTR_FORECAST_PRECIPITATION) == 1
|
||||
assert data.get(ATTR_FORECAST)[0].get(ATTR_FORECAST_PRECIPITATION_PROBABILITY) == 60
|
||||
|
|
|
@ -7,7 +7,12 @@ from unittest.mock import MagicMock, PropertyMock, patch
|
|||
|
||||
import pytest
|
||||
|
||||
from homeassistant.const import ATTR_DEVICE_CLASS, STATE_UNAVAILABLE, STATE_UNKNOWN
|
||||
from homeassistant.const import (
|
||||
ATTR_ATTRIBUTION,
|
||||
ATTR_DEVICE_CLASS,
|
||||
STATE_UNAVAILABLE,
|
||||
STATE_UNKNOWN,
|
||||
)
|
||||
from homeassistant.core import Context, HomeAssistantError
|
||||
from homeassistant.helpers import entity, entity_registry
|
||||
|
||||
|
@ -790,3 +795,17 @@ async def test_float_conversion(hass):
|
|||
state = hass.states.get("hello.world")
|
||||
assert state is not None
|
||||
assert state.state == "3.6"
|
||||
|
||||
|
||||
async def test_attribution_attribute(hass):
|
||||
"""Test attribution attribute."""
|
||||
mock_entity = entity.Entity()
|
||||
mock_entity.hass = hass
|
||||
mock_entity.entity_id = "hello.world"
|
||||
mock_entity._attr_attribution = "Home Assistant"
|
||||
|
||||
mock_entity.async_schedule_update_ha_state(True)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
state = hass.states.get(mock_entity.entity_id)
|
||||
assert state.attributes.get(ATTR_ATTRIBUTION) == "Home Assistant"
|
||||
|
|
Loading…
Reference in New Issue