Skip to content

Commit

Permalink
Move temperature conversions to sensor base class (1/8) (#48261)
Browse files Browse the repository at this point in the history
* Move temperature conversions to entity base class (1/8)

* Update integrations a-c

* Leave old temperature conversion until all integrations are migrated

* tweak

* Use contextlib.suppress

* Remove the MeasurableUnitEntity mixin

* Address comments, add tests

* Fix f-string

* Drop deprecation warning from base entity class

* Update with _attr-shorthand

* Fix rebase mistakes

* Fix additional rebase mistakes

* Only report temperature conversion once

* Fix additional rebase mistakes

* Format homeassistant/components/bbox/sensor.py

* Fix check for overidden _attr_state

* Remove test workarounds from implementation

* Remove useless None-check

* Tweaks

* Migrate new sensors a-c

* Update climacell

* Push deprecation of temperature conversion forward

* Override __repr__ in SensorEntity

* Include native_value in SensorEntity attributes

* Pylint

* Black

* Black

* Fix rebase mistakes

* black

* Fix rebase mistakes

* Revert changes in august/sensor.py

* Revert handling of unit converted restored state

* Apply code review suggestion

* Fix arlo test
  • Loading branch information
emontnemery authored Aug 11, 2021
1 parent 930c1db commit 4e07ab1
Show file tree
Hide file tree
Showing 71 changed files with 516 additions and 360 deletions.
8 changes: 4 additions & 4 deletions homeassistant/components/abode/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,14 +61,14 @@ def __init__(self, data, device, description: SensorEntityDescription):
self._attr_name = f"{device.name} {description.name}"
self._attr_unique_id = f"{device.device_uuid}-{description.key}"
if description.key == CONST.TEMP_STATUS_KEY:
self._attr_unit_of_measurement = device.temp_unit
self._attr_native_unit_of_measurement = device.temp_unit
elif description.key == CONST.HUMI_STATUS_KEY:
self._attr_unit_of_measurement = device.humidity_unit
self._attr_native_unit_of_measurement = device.humidity_unit
elif description.key == CONST.LUX_STATUS_KEY:
self._attr_unit_of_measurement = device.lux_unit
self._attr_native_unit_of_measurement = device.lux_unit

@property
def state(self):
def native_value(self):
"""Return the state of the sensor."""
if self.entity_description.key == CONST.TEMP_STATUS_KEY:
return self._device.temp
Expand Down
6 changes: 3 additions & 3 deletions homeassistant/components/accuweather/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,10 +88,10 @@ def __init__(
)
if coordinator.is_metric:
self._unit_system = API_METRIC
self._attr_unit_of_measurement = description.unit_metric
self._attr_native_unit_of_measurement = description.unit_metric
else:
self._unit_system = API_IMPERIAL
self._attr_unit_of_measurement = description.unit_imperial
self._attr_native_unit_of_measurement = description.unit_imperial
self._attr_device_info = {
"identifiers": {(DOMAIN, coordinator.location_key)},
"name": NAME,
Expand All @@ -101,7 +101,7 @@ def __init__(
self.forecast_day = forecast_day

@property
def state(self) -> StateType:
def native_value(self) -> StateType:
"""Return the state."""
if self.forecast_day is not None:
if self.entity_description.device_class == DEVICE_CLASS_TEMPERATURE:
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/acmeda/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,6 @@ def name(self):
return f"{super().name} Battery"

@property
def state(self):
def native_value(self):
"""Return the state of the device."""
return self.roller.battery
4 changes: 2 additions & 2 deletions homeassistant/components/adguard/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,12 +82,12 @@ def unique_id(self) -> str:
)

@property
def state(self) -> str | None:
def native_value(self) -> str | None:
"""Return the state of the sensor."""
return self._state

@property
def unit_of_measurement(self) -> str | None:
def native_unit_of_measurement(self) -> str | None:
"""Return the unit this state is expressed in."""
return self._unit_of_measurement

Expand Down
4 changes: 2 additions & 2 deletions homeassistant/components/ads/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ class AdsSensor(AdsEntity, SensorEntity):
def __init__(self, ads_hub, ads_var, ads_type, name, unit_of_measurement, factor):
"""Initialize AdsSensor entity."""
super().__init__(ads_hub, name, ads_var)
self._attr_unit_of_measurement = unit_of_measurement
self._attr_native_unit_of_measurement = unit_of_measurement
self._ads_type = ads_type
self._factor = factor

Expand All @@ -64,6 +64,6 @@ async def async_added_to_hass(self):
)

@property
def state(self) -> StateType:
def native_value(self) -> StateType:
"""Return the state of the device."""
return self._state_dict[STATE_KEY_STATE]
14 changes: 7 additions & 7 deletions homeassistant/components/advantage_air/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
class AdvantageAirTimeTo(AdvantageAirEntity, SensorEntity):
"""Representation of Advantage Air timer control."""

_attr_unit_of_measurement = ADVANTAGE_AIR_SET_COUNTDOWN_UNIT
_attr_native_unit_of_measurement = ADVANTAGE_AIR_SET_COUNTDOWN_UNIT

def __init__(self, instance, ac_key, action):
"""Initialize the Advantage Air timer control."""
Expand All @@ -58,7 +58,7 @@ def __init__(self, instance, ac_key, action):
)

@property
def state(self):
def native_value(self):
"""Return the current value."""
return self._ac[self._time_key]

Expand All @@ -78,7 +78,7 @@ async def set_time_to(self, **kwargs):
class AdvantageAirZoneVent(AdvantageAirEntity, SensorEntity):
"""Representation of Advantage Air Zone Vent Sensor."""

_attr_unit_of_measurement = PERCENTAGE
_attr_native_unit_of_measurement = PERCENTAGE
_attr_state_class = STATE_CLASS_MEASUREMENT

def __init__(self, instance, ac_key, zone_key):
Expand All @@ -90,7 +90,7 @@ def __init__(self, instance, ac_key, zone_key):
)

@property
def state(self):
def native_value(self):
"""Return the current value of the air vent."""
if self._zone["state"] == ADVANTAGE_AIR_STATE_OPEN:
return self._zone["value"]
Expand All @@ -107,7 +107,7 @@ def icon(self):
class AdvantageAirZoneSignal(AdvantageAirEntity, SensorEntity):
"""Representation of Advantage Air Zone wireless signal sensor."""

_attr_unit_of_measurement = PERCENTAGE
_attr_native_unit_of_measurement = PERCENTAGE
_attr_state_class = STATE_CLASS_MEASUREMENT

def __init__(self, instance, ac_key, zone_key):
Expand All @@ -119,7 +119,7 @@ def __init__(self, instance, ac_key, zone_key):
)

@property
def state(self):
def native_value(self):
"""Return the current value of the wireless signal."""
return self._zone["rssi"]

Expand All @@ -140,7 +140,7 @@ def icon(self):
class AdvantageAirZoneTemp(AdvantageAirEntity, SensorEntity):
"""Representation of Advantage Air Zone wireless signal sensor."""

_attr_unit_of_measurement = TEMP_CELSIUS
_attr_native_unit_of_measurement = TEMP_CELSIUS
_attr_state_class = STATE_CLASS_MEASUREMENT
_attr_icon = "mdi:thermometer"
_attr_entity_registry_enabled_default = False
Expand Down
6 changes: 3 additions & 3 deletions homeassistant/components/aemet/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ def __init__(
self._attr_name = f"{self._name} {self._sensor_name}"
self._attr_unique_id = self._unique_id
self._attr_device_class = sensor_configuration.get(SENSOR_DEVICE_CLASS)
self._attr_unit_of_measurement = sensor_configuration.get(SENSOR_UNIT)
self._attr_native_unit_of_measurement = sensor_configuration.get(SENSOR_UNIT)


class AemetSensor(AbstractAemetSensor):
Expand All @@ -106,7 +106,7 @@ def __init__(
self._weather_coordinator = weather_coordinator

@property
def state(self):
def native_value(self):
"""Return the state of the device."""
return self._weather_coordinator.data.get(self._sensor_type)

Expand Down Expand Up @@ -134,7 +134,7 @@ def __init__(
)

@property
def state(self):
def native_value(self):
"""Return the state of the device."""
forecast = None
forecasts = self._weather_coordinator.data.get(
Expand Down
4 changes: 2 additions & 2 deletions homeassistant/components/aftership/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ async def handle_remove_tracking(call: ServiceCall) -> None:
class AfterShipSensor(SensorEntity):
"""Representation of a AfterShip sensor."""

_attr_unit_of_measurement: str = "packages"
_attr_native_unit_of_measurement: str = "packages"
_attr_icon: str = ICON

def __init__(self, aftership: Tracking, name: str) -> None:
Expand All @@ -120,7 +120,7 @@ def __init__(self, aftership: Tracking, name: str) -> None:
self._attr_name = name

@property
def state(self) -> int | None:
def native_value(self) -> int | None:
"""Return the state of the sensor."""
return self._state

Expand Down
14 changes: 7 additions & 7 deletions homeassistant/components/airly/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,49 +50,49 @@
AirlySensorEntityDescription(
key=ATTR_API_CAQI,
name=ATTR_API_CAQI,
unit_of_measurement="CAQI",
native_unit_of_measurement="CAQI",
),
AirlySensorEntityDescription(
key=ATTR_API_PM1,
icon="mdi:blur",
name=ATTR_API_PM1,
unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
state_class=STATE_CLASS_MEASUREMENT,
),
AirlySensorEntityDescription(
key=ATTR_API_PM25,
icon="mdi:blur",
name="PM2.5",
unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
state_class=STATE_CLASS_MEASUREMENT,
),
AirlySensorEntityDescription(
key=ATTR_API_PM10,
icon="mdi:blur",
name=ATTR_API_PM10,
unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
state_class=STATE_CLASS_MEASUREMENT,
),
AirlySensorEntityDescription(
key=ATTR_API_HUMIDITY,
device_class=DEVICE_CLASS_HUMIDITY,
name=ATTR_API_HUMIDITY.capitalize(),
unit_of_measurement=PERCENTAGE,
native_unit_of_measurement=PERCENTAGE,
state_class=STATE_CLASS_MEASUREMENT,
value=lambda value: round(value, 1),
),
AirlySensorEntityDescription(
key=ATTR_API_PRESSURE,
device_class=DEVICE_CLASS_PRESSURE,
name=ATTR_API_PRESSURE.capitalize(),
unit_of_measurement=PRESSURE_HPA,
native_unit_of_measurement=PRESSURE_HPA,
state_class=STATE_CLASS_MEASUREMENT,
),
AirlySensorEntityDescription(
key=ATTR_API_TEMPERATURE,
device_class=DEVICE_CLASS_TEMPERATURE,
name=ATTR_API_TEMPERATURE.capitalize(),
unit_of_measurement=TEMP_CELSIUS,
native_unit_of_measurement=TEMP_CELSIUS,
state_class=STATE_CLASS_MEASUREMENT,
value=lambda value: round(value, 1),
),
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/airly/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ def __init__(
self.entity_description = description

@property
def state(self) -> StateType:
def native_value(self) -> StateType:
"""Return the state."""
state = self.coordinator.data[self.entity_description.key]
return cast(StateType, self.entity_description.value(state))
Expand Down
4 changes: 2 additions & 2 deletions homeassistant/components/airnow/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,11 +72,11 @@ def __init__(self, coordinator, kind):
self._attr_name = f"AirNow {SENSOR_TYPES[self.kind][ATTR_LABEL]}"
self._attr_icon = SENSOR_TYPES[self.kind][ATTR_ICON]
self._attr_device_class = SENSOR_TYPES[self.kind][ATTR_DEVICE_CLASS]
self._attr_unit_of_measurement = SENSOR_TYPES[self.kind][ATTR_UNIT]
self._attr_native_unit_of_measurement = SENSOR_TYPES[self.kind][ATTR_UNIT]
self._attr_unique_id = f"{self.coordinator.latitude}-{self.coordinator.longitude}-{self.kind.lower()}"

@property
def state(self):
def native_value(self):
"""Return the state."""
self._state = self.coordinator.data[self.kind]
return self._state
Expand Down
36 changes: 21 additions & 15 deletions homeassistant/components/airvisual/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ def __init__(
self._attr_icon = icon
self._attr_name = f"{GEOGRAPHY_SENSOR_LOCALES[locale]} {name}"
self._attr_unique_id = f"{config_entry.unique_id}_{locale}_{kind}"
self._attr_unit_of_measurement = unit
self._attr_native_unit_of_measurement = unit
self._config_entry = config_entry
self._kind = kind
self._locale = locale
Expand All @@ -232,16 +232,16 @@ def update_from_latest_data(self) -> None:

if self._kind == SENSOR_KIND_LEVEL:
aqi = data[f"aqi{self._locale}"]
[(self._attr_state, self._attr_icon)] = [
[(self._attr_native_value, self._attr_icon)] = [
(name, icon)
for (floor, ceiling), (name, icon) in POLLUTANT_LEVELS.items()
if floor <= aqi <= ceiling
]
elif self._kind == SENSOR_KIND_AQI:
self._attr_state = data[f"aqi{self._locale}"]
self._attr_native_value = data[f"aqi{self._locale}"]
elif self._kind == SENSOR_KIND_POLLUTANT:
symbol = data[f"main{self._locale}"]
self._attr_state = symbol
self._attr_native_value = symbol
self._attr_extra_state_attributes.update(
{
ATTR_POLLUTANT_SYMBOL: symbol,
Expand Down Expand Up @@ -298,7 +298,7 @@ def __init__(
f"{coordinator.data['settings']['node_name']} Node/Pro: {name}"
)
self._attr_unique_id = f"{coordinator.data['serial_number']}_{kind}"
self._attr_unit_of_measurement = unit
self._attr_native_unit_of_measurement = unit
self._kind = kind

@property
Expand All @@ -320,24 +320,30 @@ def update_from_latest_data(self) -> None:
"""Update the entity from the latest data."""
if self._kind == SENSOR_KIND_AQI:
if self.coordinator.data["settings"]["is_aqi_usa"]:
self._attr_state = self.coordinator.data["measurements"]["aqi_us"]
self._attr_native_value = self.coordinator.data["measurements"][
"aqi_us"
]
else:
self._attr_state = self.coordinator.data["measurements"]["aqi_cn"]
self._attr_native_value = self.coordinator.data["measurements"][
"aqi_cn"
]
elif self._kind == SENSOR_KIND_BATTERY_LEVEL:
self._attr_state = self.coordinator.data["status"]["battery"]
self._attr_native_value = self.coordinator.data["status"]["battery"]
elif self._kind == SENSOR_KIND_CO2:
self._attr_state = self.coordinator.data["measurements"].get("co2")
self._attr_native_value = self.coordinator.data["measurements"].get("co2")
elif self._kind == SENSOR_KIND_HUMIDITY:
self._attr_state = self.coordinator.data["measurements"].get("humidity")
self._attr_native_value = self.coordinator.data["measurements"].get(
"humidity"
)
elif self._kind == SENSOR_KIND_PM_0_1:
self._attr_state = self.coordinator.data["measurements"].get("pm0_1")
self._attr_native_value = self.coordinator.data["measurements"].get("pm0_1")
elif self._kind == SENSOR_KIND_PM_1_0:
self._attr_state = self.coordinator.data["measurements"].get("pm1_0")
self._attr_native_value = self.coordinator.data["measurements"].get("pm1_0")
elif self._kind == SENSOR_KIND_PM_2_5:
self._attr_state = self.coordinator.data["measurements"].get("pm2_5")
self._attr_native_value = self.coordinator.data["measurements"].get("pm2_5")
elif self._kind == SENSOR_KIND_TEMPERATURE:
self._attr_state = self.coordinator.data["measurements"].get(
self._attr_native_value = self.coordinator.data["measurements"].get(
"temperature_C"
)
elif self._kind == SENSOR_KIND_VOC:
self._attr_state = self.coordinator.data["measurements"].get("voc")
self._attr_native_value = self.coordinator.data["measurements"].get("voc")
4 changes: 2 additions & 2 deletions homeassistant/components/alarmdecoder/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,6 @@ async def async_added_to_hass(self):
)

def _message_callback(self, message):
if self._attr_state != message.text:
self._attr_state = message.text
if self._attr_native_value != message.text:
self._attr_native_value = message.text
self.schedule_update_ha_state()
8 changes: 4 additions & 4 deletions homeassistant/components/alpha_vantage/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,15 +112,15 @@ def __init__(self, timeseries, symbol):
self._symbol = symbol[CONF_SYMBOL]
self._attr_name = symbol.get(CONF_NAME, self._symbol)
self._timeseries = timeseries
self._attr_unit_of_measurement = symbol.get(CONF_CURRENCY, self._symbol)
self._attr_native_unit_of_measurement = symbol.get(CONF_CURRENCY, self._symbol)
self._attr_icon = ICONS.get(symbol.get(CONF_CURRENCY, "USD"))

def update(self):
"""Get the latest data and updates the states."""
_LOGGER.debug("Requesting new data for symbol %s", self._symbol)
all_values, _ = self._timeseries.get_intraday(self._symbol)
values = next(iter(all_values.values()))
self._attr_state = values["1. open"]
self._attr_native_value = values["1. open"]
self._attr_extra_state_attributes = (
{
ATTR_ATTRIBUTION: ATTRIBUTION,
Expand Down Expand Up @@ -148,7 +148,7 @@ def __init__(self, foreign_exchange, config):
else f"{self._to_currency}/{self._from_currency}"
)
self._attr_icon = ICONS.get(self._from_currency, "USD")
self._attr_unit_of_measurement = self._to_currency
self._attr_native_unit_of_measurement = self._to_currency

def update(self):
"""Get the latest data and updates the states."""
Expand All @@ -160,7 +160,7 @@ def update(self):
values, _ = self._foreign_exchange.get_currency_exchange_rate(
from_currency=self._from_currency, to_currency=self._to_currency
)
self._attr_state = round(float(values["5. Exchange Rate"]), 4)
self._attr_native_value = round(float(values["5. Exchange Rate"]), 4)
self._attr_extra_state_attributes = (
{
ATTR_ATTRIBUTION: ATTRIBUTION,
Expand Down
Loading

0 comments on commit 4e07ab1

Please sign in to comment.