Define entity attributes as entity class variables (#50925)
* Define entity attributes as entity class variables * Example coronavirus integration * Example verisure * Cleanup/typing fixes * Fix Coronavirus * Revert "Fix Coronavirus" This reverts commit060843860f
. * Revert "Cleanup/typing fixes" This reverts commit659b79e75a
. * Define entity attributes as entity class variables (attr alternative) * Example coronavirus * Example nut * Example verisure * Mark private * Cleanup after all reverting/cherrypicking/merging * Implement all entity properties * Update coronavirus example * Update nut example * Update verisure example * Lets not talk about this one... * Fix multiple class attribute
This commit is contained in:
parent
b9a0fb93eb
commit
38d095aa18
9 changed files with 80 additions and 173 deletions
|
@ -27,17 +27,21 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
|
|||
class CoronavirusSensor(CoordinatorEntity, SensorEntity):
|
||||
"""Sensor representing corona virus data."""
|
||||
|
||||
name = None
|
||||
unique_id = None
|
||||
_attr_unit_of_measurement = "people"
|
||||
|
||||
def __init__(self, coordinator, country, info_type):
|
||||
"""Initialize coronavirus sensor."""
|
||||
super().__init__(coordinator)
|
||||
self._attr_extra_state_attributes = {ATTR_ATTRIBUTION: ATTRIBUTION}
|
||||
self._attr_icon = SENSORS[info_type]
|
||||
self._attr_unique_id = f"{country}-{info_type}"
|
||||
if country == OPTION_WORLDWIDE:
|
||||
self.name = f"Worldwide Coronavirus {info_type}"
|
||||
self._attr_name = f"Worldwide Coronavirus {info_type}"
|
||||
else:
|
||||
self.name = f"{coordinator.data[country].country} Coronavirus {info_type}"
|
||||
self.unique_id = f"{country}-{info_type}"
|
||||
self._attr_name = (
|
||||
f"{coordinator.data[country].country} Coronavirus {info_type}"
|
||||
)
|
||||
|
||||
self.country = country
|
||||
self.info_type = info_type
|
||||
|
||||
|
@ -62,18 +66,3 @@ class CoronavirusSensor(CoordinatorEntity, SensorEntity):
|
|||
return sum_cases
|
||||
|
||||
return getattr(self.coordinator.data[self.country], self.info_type)
|
||||
|
||||
@property
|
||||
def icon(self):
|
||||
"""Return the icon."""
|
||||
return SENSORS[self.info_type]
|
||||
|
||||
@property
|
||||
def unit_of_measurement(self):
|
||||
"""Return unit of measurement."""
|
||||
return "people"
|
||||
|
||||
@property
|
||||
def extra_state_attributes(self):
|
||||
"""Return device attributes."""
|
||||
return {ATTR_ATTRIBUTION: ATTRIBUTION}
|
||||
|
|
|
@ -98,11 +98,14 @@ class NUTSensor(CoordinatorEntity, SensorEntity):
|
|||
self._firmware = firmware
|
||||
self._model = model
|
||||
self._device_name = name
|
||||
self._name = f"{name} {SENSOR_TYPES[sensor_type][SENSOR_NAME]}"
|
||||
self._unit = SENSOR_TYPES[sensor_type][SENSOR_UNIT]
|
||||
self._data = data
|
||||
self._unique_id = unique_id
|
||||
|
||||
self._attr_device_class = SENSOR_TYPES[self._type][SENSOR_DEVICE_CLASS]
|
||||
self._attr_icon = SENSOR_TYPES[self._type][SENSOR_ICON]
|
||||
self._attr_name = f"{name} {SENSOR_TYPES[sensor_type][SENSOR_NAME]}"
|
||||
self._attr_unit_of_measurement = SENSOR_TYPES[sensor_type][SENSOR_UNIT]
|
||||
|
||||
@property
|
||||
def device_info(self):
|
||||
"""Device info for the ups."""
|
||||
|
@ -127,25 +130,6 @@ class NUTSensor(CoordinatorEntity, SensorEntity):
|
|||
return None
|
||||
return f"{self._unique_id}_{self._type}"
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
"""Return the name of the UPS sensor."""
|
||||
return self._name
|
||||
|
||||
@property
|
||||
def icon(self):
|
||||
"""Icon to use in the frontend, if any."""
|
||||
if SENSOR_TYPES[self._type][SENSOR_DEVICE_CLASS]:
|
||||
# The UI will assign an icon
|
||||
# if it has a class
|
||||
return None
|
||||
return SENSOR_TYPES[self._type][SENSOR_ICON]
|
||||
|
||||
@property
|
||||
def device_class(self):
|
||||
"""Device class of the sensor."""
|
||||
return SENSOR_TYPES[self._type][SENSOR_DEVICE_CLASS]
|
||||
|
||||
@property
|
||||
def state(self):
|
||||
"""Return entity state from ups."""
|
||||
|
@ -155,11 +139,6 @@ class NUTSensor(CoordinatorEntity, SensorEntity):
|
|||
return _format_display_state(self._data.status)
|
||||
return self._data.status.get(self._type)
|
||||
|
||||
@property
|
||||
def unit_of_measurement(self):
|
||||
"""Return the unit of measurement of this entity, if any."""
|
||||
return self._unit
|
||||
|
||||
@property
|
||||
def extra_state_attributes(self):
|
||||
"""Return the sensor attributes."""
|
||||
|
|
|
@ -35,18 +35,10 @@ class VerisureAlarm(CoordinatorEntity, AlarmControlPanelEntity):
|
|||
|
||||
coordinator: VerisureDataUpdateCoordinator
|
||||
|
||||
_attr_name = "Verisure Alarm"
|
||||
_attr_supported_features = SUPPORT_ALARM_ARM_HOME | SUPPORT_ALARM_ARM_AWAY
|
||||
|
||||
_changed_by: str | None = None
|
||||
_state: str | None = None
|
||||
|
||||
@property
|
||||
def name(self) -> str:
|
||||
"""Return the name of the entity."""
|
||||
return "Verisure Alarm"
|
||||
|
||||
@property
|
||||
def unique_id(self) -> str:
|
||||
"""Return the unique ID for this entity."""
|
||||
return self.coordinator.entry.data[CONF_GIID]
|
||||
|
||||
@property
|
||||
def device_info(self) -> DeviceInfo:
|
||||
|
@ -58,11 +50,6 @@ class VerisureAlarm(CoordinatorEntity, AlarmControlPanelEntity):
|
|||
"identifiers": {(DOMAIN, self.coordinator.entry.data[CONF_GIID])},
|
||||
}
|
||||
|
||||
@property
|
||||
def state(self) -> str | None:
|
||||
"""Return the state of the entity."""
|
||||
return self._state
|
||||
|
||||
@property
|
||||
def supported_features(self) -> int:
|
||||
"""Return the list of supported features."""
|
||||
|
@ -109,7 +96,7 @@ class VerisureAlarm(CoordinatorEntity, AlarmControlPanelEntity):
|
|||
@callback
|
||||
def _handle_coordinator_update(self) -> None:
|
||||
"""Handle updated data from the coordinator."""
|
||||
self._state = ALARM_STATE_TO_HA.get(
|
||||
self._attr_state = ALARM_STATE_TO_HA.get(
|
||||
self.coordinator.data["alarm"]["statusType"]
|
||||
)
|
||||
self._changed_by = self.coordinator.data["alarm"].get("name")
|
||||
|
|
|
@ -39,23 +39,17 @@ class VerisureDoorWindowSensor(CoordinatorEntity, BinarySensorEntity):
|
|||
|
||||
coordinator: VerisureDataUpdateCoordinator
|
||||
|
||||
_attr_device_class = DEVICE_CLASS_OPENING
|
||||
|
||||
def __init__(
|
||||
self, coordinator: VerisureDataUpdateCoordinator, serial_number: str
|
||||
) -> None:
|
||||
"""Initialize the Verisure door window sensor."""
|
||||
super().__init__(coordinator)
|
||||
self._attr_name = coordinator.data["door_window"][serial_number]["area"]
|
||||
self._attr_unique_id = f"{serial_number}_door_window"
|
||||
self.serial_number = serial_number
|
||||
|
||||
@property
|
||||
def name(self) -> str:
|
||||
"""Return the name of this entity."""
|
||||
return self.coordinator.data["door_window"][self.serial_number]["area"]
|
||||
|
||||
@property
|
||||
def unique_id(self) -> str:
|
||||
"""Return the unique ID for this entity."""
|
||||
return f"{self.serial_number}_door_window"
|
||||
|
||||
@property
|
||||
def device_info(self) -> DeviceInfo:
|
||||
"""Return device information about this entity."""
|
||||
|
@ -69,11 +63,6 @@ class VerisureDoorWindowSensor(CoordinatorEntity, BinarySensorEntity):
|
|||
"via_device": (DOMAIN, self.coordinator.entry.data[CONF_GIID]),
|
||||
}
|
||||
|
||||
@property
|
||||
def device_class(self) -> str:
|
||||
"""Return the class of this entity."""
|
||||
return DEVICE_CLASS_OPENING
|
||||
|
||||
@property
|
||||
def is_on(self) -> bool:
|
||||
"""Return the state of the sensor."""
|
||||
|
@ -95,10 +84,8 @@ class VerisureEthernetStatus(CoordinatorEntity, BinarySensorEntity):
|
|||
|
||||
coordinator: VerisureDataUpdateCoordinator
|
||||
|
||||
@property
|
||||
def name(self) -> str:
|
||||
"""Return the name of this entity."""
|
||||
return "Verisure Ethernet status"
|
||||
_attr_name = "Verisure Ethernet status"
|
||||
_attr_device_class = DEVICE_CLASS_CONNECTIVITY
|
||||
|
||||
@property
|
||||
def unique_id(self) -> str:
|
||||
|
@ -124,8 +111,3 @@ class VerisureEthernetStatus(CoordinatorEntity, BinarySensorEntity):
|
|||
def available(self) -> bool:
|
||||
"""Return True if entity is available."""
|
||||
return super().available and self.coordinator.data["ethernet"] is not None
|
||||
|
||||
@property
|
||||
def device_class(self) -> str:
|
||||
"""Return the class of this entity."""
|
||||
return DEVICE_CLASS_CONNECTIVITY
|
||||
|
|
|
@ -58,21 +58,14 @@ class VerisureSmartcam(CoordinatorEntity, Camera):
|
|||
super().__init__(coordinator)
|
||||
Camera.__init__(self)
|
||||
|
||||
self._attr_name = coordinator.data["cameras"][serial_number]["area"]
|
||||
self._attr_unique_id = serial_number
|
||||
|
||||
self.serial_number = serial_number
|
||||
self._directory_path = directory_path
|
||||
self._image = None
|
||||
self._image_id = None
|
||||
|
||||
@property
|
||||
def name(self) -> str:
|
||||
"""Return the name of this entity."""
|
||||
return self.coordinator.data["cameras"][self.serial_number]["area"]
|
||||
|
||||
@property
|
||||
def unique_id(self) -> str:
|
||||
"""Return the unique ID for this entity."""
|
||||
return self.serial_number
|
||||
|
||||
@property
|
||||
def device_info(self) -> DeviceInfo:
|
||||
"""Return device information about this entity."""
|
||||
|
|
|
@ -65,22 +65,16 @@ class VerisureDoorlock(CoordinatorEntity, LockEntity):
|
|||
) -> None:
|
||||
"""Initialize the Verisure lock."""
|
||||
super().__init__(coordinator)
|
||||
|
||||
self._attr_name = coordinator.data["locks"][serial_number]["area"]
|
||||
self._attr_unique_id = serial_number
|
||||
|
||||
self.serial_number = serial_number
|
||||
self._state = None
|
||||
self._digits = coordinator.entry.options.get(
|
||||
CONF_LOCK_CODE_DIGITS, DEFAULT_LOCK_CODE_DIGITS
|
||||
)
|
||||
|
||||
@property
|
||||
def name(self) -> str:
|
||||
"""Return the name of this entity."""
|
||||
return self.coordinator.data["locks"][self.serial_number]["area"]
|
||||
|
||||
@property
|
||||
def unique_id(self) -> str:
|
||||
"""Return the unique ID for this entity."""
|
||||
return self.serial_number
|
||||
|
||||
@property
|
||||
def device_info(self) -> DeviceInfo:
|
||||
"""Return device information about this entity."""
|
||||
|
|
|
@ -50,11 +50,15 @@ class VerisureThermometer(CoordinatorEntity, SensorEntity):
|
|||
|
||||
coordinator: VerisureDataUpdateCoordinator
|
||||
|
||||
_attr_device_class = DEVICE_CLASS_TEMPERATURE
|
||||
_attr_unit_of_measurement = TEMP_CELSIUS
|
||||
|
||||
def __init__(
|
||||
self, coordinator: VerisureDataUpdateCoordinator, serial_number: str
|
||||
) -> None:
|
||||
"""Initialize the sensor."""
|
||||
super().__init__(coordinator)
|
||||
self._attr_unique_id = f"{serial_number}_temperature"
|
||||
self.serial_number = serial_number
|
||||
|
||||
@property
|
||||
|
@ -63,16 +67,6 @@ class VerisureThermometer(CoordinatorEntity, SensorEntity):
|
|||
name = self.coordinator.data["climate"][self.serial_number]["deviceArea"]
|
||||
return f"{name} Temperature"
|
||||
|
||||
@property
|
||||
def unique_id(self) -> str:
|
||||
"""Return the unique ID for this entity."""
|
||||
return f"{self.serial_number}_temperature"
|
||||
|
||||
@property
|
||||
def device_class(self) -> str:
|
||||
"""Return the class of this entity."""
|
||||
return DEVICE_CLASS_TEMPERATURE
|
||||
|
||||
@property
|
||||
def device_info(self) -> DeviceInfo:
|
||||
"""Return device information about this entity."""
|
||||
|
@ -103,22 +97,21 @@ class VerisureThermometer(CoordinatorEntity, SensorEntity):
|
|||
and "temperature" in self.coordinator.data["climate"][self.serial_number]
|
||||
)
|
||||
|
||||
@property
|
||||
def unit_of_measurement(self) -> str:
|
||||
"""Return the unit of measurement of this entity."""
|
||||
return TEMP_CELSIUS
|
||||
|
||||
|
||||
class VerisureHygrometer(CoordinatorEntity, SensorEntity):
|
||||
"""Representation of a Verisure hygrometer."""
|
||||
|
||||
coordinator: VerisureDataUpdateCoordinator
|
||||
|
||||
_attr_device_class = DEVICE_CLASS_HUMIDITY
|
||||
_attr_unit_of_measurement = PERCENTAGE
|
||||
|
||||
def __init__(
|
||||
self, coordinator: VerisureDataUpdateCoordinator, serial_number: str
|
||||
) -> None:
|
||||
"""Initialize the sensor."""
|
||||
super().__init__(coordinator)
|
||||
self._attr_unique_id = f"{serial_number}_humidity"
|
||||
self.serial_number = serial_number
|
||||
|
||||
@property
|
||||
|
@ -127,16 +120,6 @@ class VerisureHygrometer(CoordinatorEntity, SensorEntity):
|
|||
name = self.coordinator.data["climate"][self.serial_number]["deviceArea"]
|
||||
return f"{name} Humidity"
|
||||
|
||||
@property
|
||||
def unique_id(self) -> str:
|
||||
"""Return the unique ID for this entity."""
|
||||
return f"{self.serial_number}_humidity"
|
||||
|
||||
@property
|
||||
def device_class(self) -> str:
|
||||
"""Return the class of this entity."""
|
||||
return DEVICE_CLASS_HUMIDITY
|
||||
|
||||
@property
|
||||
def device_info(self) -> DeviceInfo:
|
||||
"""Return device information about this entity."""
|
||||
|
@ -167,22 +150,20 @@ class VerisureHygrometer(CoordinatorEntity, SensorEntity):
|
|||
and "humidity" in self.coordinator.data["climate"][self.serial_number]
|
||||
)
|
||||
|
||||
@property
|
||||
def unit_of_measurement(self) -> str:
|
||||
"""Return the unit of measurement of this entity."""
|
||||
return PERCENTAGE
|
||||
|
||||
|
||||
class VerisureMouseDetection(CoordinatorEntity, SensorEntity):
|
||||
"""Representation of a Verisure mouse detector."""
|
||||
|
||||
coordinator: VerisureDataUpdateCoordinator
|
||||
|
||||
_attr_unit_of_measurement = "Mice"
|
||||
|
||||
def __init__(
|
||||
self, coordinator: VerisureDataUpdateCoordinator, serial_number: str
|
||||
) -> None:
|
||||
"""Initialize the sensor."""
|
||||
super().__init__(coordinator)
|
||||
self._attr_unique_id = f"{serial_number}_mice"
|
||||
self.serial_number = serial_number
|
||||
|
||||
@property
|
||||
|
@ -191,11 +172,6 @@ class VerisureMouseDetection(CoordinatorEntity, SensorEntity):
|
|||
name = self.coordinator.data["mice"][self.serial_number]["area"]
|
||||
return f"{name} Mouse"
|
||||
|
||||
@property
|
||||
def unique_id(self) -> str:
|
||||
"""Return the unique ID for this entity."""
|
||||
return f"{self.serial_number}_mice"
|
||||
|
||||
@property
|
||||
def device_info(self) -> DeviceInfo:
|
||||
"""Return device information about this entity."""
|
||||
|
@ -222,8 +198,3 @@ class VerisureMouseDetection(CoordinatorEntity, SensorEntity):
|
|||
and self.serial_number in self.coordinator.data["mice"]
|
||||
and "detections" in self.coordinator.data["mice"][self.serial_number]
|
||||
)
|
||||
|
||||
@property
|
||||
def unit_of_measurement(self) -> str:
|
||||
"""Return the unit of measurement of this entity."""
|
||||
return "Mice"
|
||||
|
|
|
@ -37,20 +37,14 @@ class VerisureSmartplug(CoordinatorEntity, SwitchEntity):
|
|||
) -> None:
|
||||
"""Initialize the Verisure device."""
|
||||
super().__init__(coordinator)
|
||||
|
||||
self._attr_name = coordinator.data["smart_plugs"][serial_number]["area"]
|
||||
self._attr_unique_id = serial_number
|
||||
|
||||
self.serial_number = serial_number
|
||||
self._change_timestamp = 0
|
||||
self._state = False
|
||||
|
||||
@property
|
||||
def name(self) -> str:
|
||||
"""Return the name of this entity."""
|
||||
return self.coordinator.data["smart_plugs"][self.serial_number]["area"]
|
||||
|
||||
@property
|
||||
def unique_id(self) -> str:
|
||||
"""Return the unique ID for this entity."""
|
||||
return self.serial_number
|
||||
|
||||
@property
|
||||
def device_info(self) -> DeviceInfo:
|
||||
"""Return device information about this entity."""
|
||||
|
|
|
@ -168,28 +168,46 @@ class Entity(ABC):
|
|||
# If entity is added to an entity platform
|
||||
_added = False
|
||||
|
||||
# Entity Properties
|
||||
_attr_assumed_state: bool = False
|
||||
_attr_available: bool = True
|
||||
_attr_context_recent_time: timedelta = timedelta(seconds=5)
|
||||
_attr_device_class: str | None = None
|
||||
_attr_device_info: DeviceInfo | None = None
|
||||
_attr_entity_picture: str | None = None
|
||||
_attr_entity_registry_enabled_default: bool = True
|
||||
_attr_extra_state_attributes: Mapping[str, Any] | None = None
|
||||
_attr_force_update: bool = False
|
||||
_attr_icon: str | None = None
|
||||
_attr_name: str | None = None
|
||||
_attr_should_poll: bool = True
|
||||
_attr_state: StateType = STATE_UNKNOWN
|
||||
_attr_supported_features: int | None = None
|
||||
_attr_unique_id: str | None = None
|
||||
_attr_unit_of_measurement: str | None = None
|
||||
|
||||
@property
|
||||
def should_poll(self) -> bool:
|
||||
"""Return True if entity has to be polled for state.
|
||||
|
||||
False if entity pushes its state to HA.
|
||||
"""
|
||||
return True
|
||||
return self._attr_should_poll
|
||||
|
||||
@property
|
||||
def unique_id(self) -> str | None:
|
||||
"""Return a unique ID."""
|
||||
return None
|
||||
return self._attr_unique_id
|
||||
|
||||
@property
|
||||
def name(self) -> str | None:
|
||||
"""Return the name of the entity."""
|
||||
return None
|
||||
return self._attr_name
|
||||
|
||||
@property
|
||||
def state(self) -> StateType:
|
||||
"""Return the state of the entity."""
|
||||
return STATE_UNKNOWN
|
||||
return self._attr_state
|
||||
|
||||
@property
|
||||
def capability_attributes(self) -> Mapping[str, Any] | None:
|
||||
|
@ -227,7 +245,7 @@ class Entity(ABC):
|
|||
Implemented by platform classes. Convention for attribute names
|
||||
is lowercase snake_case.
|
||||
"""
|
||||
return None
|
||||
return self._attr_extra_state_attributes
|
||||
|
||||
@property
|
||||
def device_info(self) -> DeviceInfo | None:
|
||||
|
@ -235,37 +253,37 @@ class Entity(ABC):
|
|||
|
||||
Implemented by platform classes.
|
||||
"""
|
||||
return None
|
||||
return self._attr_device_info
|
||||
|
||||
@property
|
||||
def device_class(self) -> str | None:
|
||||
"""Return the class of this device, from component DEVICE_CLASSES."""
|
||||
return None
|
||||
return self._attr_device_class
|
||||
|
||||
@property
|
||||
def unit_of_measurement(self) -> str | None:
|
||||
"""Return the unit of measurement of this entity, if any."""
|
||||
return None
|
||||
return self._attr_unit_of_measurement
|
||||
|
||||
@property
|
||||
def icon(self) -> str | None:
|
||||
"""Return the icon to use in the frontend, if any."""
|
||||
return None
|
||||
return self._attr_icon
|
||||
|
||||
@property
|
||||
def entity_picture(self) -> str | None:
|
||||
"""Return the entity picture to use in the frontend, if any."""
|
||||
return None
|
||||
return self._attr_entity_picture
|
||||
|
||||
@property
|
||||
def available(self) -> bool:
|
||||
"""Return True if entity is available."""
|
||||
return True
|
||||
return self._attr_available
|
||||
|
||||
@property
|
||||
def assumed_state(self) -> bool:
|
||||
"""Return True if unable to access real state of the entity."""
|
||||
return False
|
||||
return self._attr_assumed_state
|
||||
|
||||
@property
|
||||
def force_update(self) -> bool:
|
||||
|
@ -274,22 +292,22 @@ class Entity(ABC):
|
|||
If True, a state change will be triggered anytime the state property is
|
||||
updated, not just when the value changes.
|
||||
"""
|
||||
return False
|
||||
return self._attr_force_update
|
||||
|
||||
@property
|
||||
def supported_features(self) -> int | None:
|
||||
"""Flag supported features."""
|
||||
return None
|
||||
return self._attr_supported_features
|
||||
|
||||
@property
|
||||
def context_recent_time(self) -> timedelta:
|
||||
"""Time that a context is considered recent."""
|
||||
return timedelta(seconds=5)
|
||||
return self._attr_context_recent_time
|
||||
|
||||
@property
|
||||
def entity_registry_enabled_default(self) -> bool:
|
||||
"""Return if the entity should be enabled when first added to the entity registry."""
|
||||
return True
|
||||
return self._attr_entity_registry_enabled_default
|
||||
|
||||
# DO NOT OVERWRITE
|
||||
# These properties and methods are either managed by Home Assistant or they
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue