diff --git a/custom_components/tesla_custom/base.py b/custom_components/tesla_custom/base.py index 464ca076..4895a400 100644 --- a/custom_components/tesla_custom/base.py +++ b/custom_components/tesla_custom/base.py @@ -1,6 +1,5 @@ """Support for Tesla cars and energy sites.""" -from homeassistant.core import callback from homeassistant.helpers.entity import DeviceInfo from homeassistant.helpers.update_coordinator import CoordinatorEntity from homeassistant.util import slugify @@ -21,30 +20,20 @@ class TeslaBaseEntity(CoordinatorEntity[TeslaDataUpdateCoordinator]): _enabled_by_default: bool = True _memorized_unique_id: str | None = None - @callback - def refresh(self) -> None: - """Refresh the device data. - - This is called by the DataUpdateCoordinator when new data is available. - - This assumes the controller has already been updated. This should be - called by inherited classes so the overall device information is updated. - """ - self.async_write_ha_state() - - @property - def name(self) -> str: - """Return device name.""" - return self.type.capitalize() - - @property - def entity_registry_enabled_default(self) -> bool: - """Set entity registry to default.""" - return self._enabled_by_default + def __init__( + self, base_unique_id: str, coordinator: TeslaDataUpdateCoordinator + ) -> None: + """Initialise the Tesla device.""" + super().__init__(coordinator) + self._attr_unique_id = slugify(f"{base_unique_id} {self.type}") + self._attr_name = self.type.capitalize() + self._attr_entity_registry_enabled_default = self._enabled_by_default async def async_added_to_hass(self) -> None: """Register state update callback.""" - self.async_on_remove(self.coordinator.async_add_listener(self.refresh)) + self.async_on_remove( + self.coordinator.async_add_listener(self.async_write_ha_state) + ) class TeslaCarEntity(TeslaBaseEntity): @@ -56,8 +45,22 @@ def __init__( coordinator: TeslaDataUpdateCoordinator, ) -> None: """Initialise the Tesla car device.""" - super().__init__(coordinator) + vin = car.vin + super().__init__(vin, coordinator) self._car = car + display_name = car.display_name + vehicle_name = ( + display_name + if display_name is not None and display_name != vin[-6:] + else f"Tesla Model {str(vin[3]).upper()}" + ) + self._attr_device_info = DeviceInfo( + identifiers={(DOMAIN, car.id)}, + name=vehicle_name, + manufacturer="Tesla", + model=car.car_type, + sw_version=car.car_version, + ) async def update_controller( self, *, wake_if_asleep: bool = False, force: bool = True, blocking: bool = True @@ -81,35 +84,6 @@ async def update_controller( ) await self.coordinator.async_refresh() - @property - def vehicle_name(self) -> str: - """Return vehicle name.""" - display_name = self._car.display_name - vin = self._car.vin - return ( - display_name - if display_name is not None and display_name != vin[-6:] - else f"Tesla Model {str(vin[3]).upper()}" - ) - - @property - def unique_id(self) -> str: - """Return unique id for car entity.""" - if not self._memorized_unique_id: - self._memorized_unique_id = slugify(f"{self._car.vin} {self.type}") - return self._memorized_unique_id - - @property - def device_info(self) -> DeviceInfo: - """Return device info.""" - return DeviceInfo( - identifiers={(DOMAIN, self._car.id)}, - name=self.vehicle_name, - manufacturer="Tesla", - model=self._car.car_type, - sw_version=self._car.car_version, - ) - @property def assumed_state(self) -> bool: """Return whether the data is from an online vehicle.""" @@ -131,34 +105,18 @@ def __init__( coordinator: TeslaDataUpdateCoordinator, ) -> None: """Initialise the Tesla energy device.""" - super().__init__(coordinator) + energysite_id = energysite.energysite_id + super().__init__(energysite_id, coordinator) self._energysite = energysite - - @property - def unique_id(self) -> str: - """Return unique id for energy site device.""" - if not self._memorized_unique_id: - self._memorized_unique_id = slugify( - f"{self._energysite.energysite_id} {self.type}" - ) - return self._memorized_unique_id - - @property - def sw_version(self) -> bool: - """Return firmware version.""" - if self._energysite.resource_type == RESOURCE_TYPE_BATTERY: - return self._energysite.version - # Non-Powerwall sites do not provide version info - return "Unavailable" - - @property - def device_info(self) -> DeviceInfo: - """Return device info.""" - model = f"{self._energysite.resource_type.title()}" - return DeviceInfo( - identifiers={(DOMAIN, self._energysite.energysite_id)}, + if energysite.resource_type == RESOURCE_TYPE_BATTERY: + sw_version = energysite.version + else: + # Non-Powerwall sites do not provide version info + sw_version = "Unavailable" + self._attr_device_info = DeviceInfo( + identifiers={(DOMAIN, energysite_id)}, manufacturer="Tesla", - model=model, - name=self._energysite.site_name, - sw_version=self.sw_version, + model=energysite.resource_type.title(), + name=energysite.site_name, + sw_version=sw_version, ) diff --git a/custom_components/tesla_custom/button.py b/custom_components/tesla_custom/button.py index c65698d7..4cc3a10d 100644 --- a/custom_components/tesla_custom/button.py +++ b/custom_components/tesla_custom/button.py @@ -101,9 +101,9 @@ def __init__( coordinator: TeslaDataUpdateCoordinator, ) -> None: """Initialise Homelink button.""" - super().__init__(car, coordinator) # Entity is only enabled upon first install if garages have been paired to homelink - self._enabled_by_default = self._car.homelink_device_count + self._enabled_by_default = car.homelink_device_count + super().__init__(car, coordinator) @property def available(self) -> bool: @@ -139,8 +139,8 @@ def __init__( coordinator: TeslaDataUpdateCoordinator, ) -> None: """Initialize emissions test button.""" + self._enabled_by_default = car.pedestrian_speaker super().__init__(car, coordinator) - self._enabled_by_default = self._car.pedestrian_speaker async def async_press(self) -> None: """Handle the button press.""" diff --git a/custom_components/tesla_custom/select.py b/custom_components/tesla_custom/select.py index 55074bb9..3d3e8e75 100644 --- a/custom_components/tesla_custom/select.py +++ b/custom_components/tesla_custom/select.py @@ -123,13 +123,13 @@ def __init__( seat_name: str, ): """Initialize heated seat entity.""" - super().__init__(car, coordinator) self._seat_name = seat_name self.type = f"heated seat {seat_name}" if SEAT_ID_MAP[self._seat_name] < 2: self._is_auto_available = True else: self._is_auto_available = False + super().__init__(car, coordinator) async def async_select_option(self, option: str, **kwargs): """Change the selected option.""" @@ -195,8 +195,8 @@ def __init__( coordinator: TeslaDataUpdateCoordinator, ): """Initialize heated seat entity.""" + self._enabled_by_default = car.steering_wheel_heater super().__init__(car, coordinator) - self._enabled_by_default = self._car.steering_wheel_heater async def async_select_option(self, option: str, **kwargs): """Change the selected option.""" diff --git a/custom_components/tesla_custom/sensor.py b/custom_components/tesla_custom/sensor.py index 3b6baa0a..59f81c8a 100644 --- a/custom_components/tesla_custom/sensor.py +++ b/custom_components/tesla_custom/sensor.py @@ -347,12 +347,12 @@ def __init__( inside=False, ) -> None: """Initialize temp entity.""" - super().__init__(car, coordinator) self.inside = inside if inside is True: self.type += " (inside)" else: self.type += " (outside)" + super().__init__(car, coordinator) @property def native_value(self) -> float: @@ -376,7 +376,6 @@ def __init__( sensor_type: str, ) -> None: """Initialize power sensor.""" - super().__init__(energysite, coordinator) self.type = sensor_type if self.type == "solar power": self._attr_icon = "mdi:solar-power-variant" @@ -386,6 +385,7 @@ def __init__( self._attr_icon = "mdi:home-lightning-bolt" if self.type == "battery power": self._attr_icon = "mdi:home-battery" + super().__init__(energysite, coordinator) @property def native_value(self) -> float: @@ -537,9 +537,9 @@ def __init__( tpms_sensor: str, ) -> None: """Initialize TPMS Pressure sensor.""" - super().__init__(car, coordinator) self._tpms_sensor = tpms_sensor self.type = tpms_sensor + super().__init__(car, coordinator) @property def native_value(self) -> float: diff --git a/custom_components/tesla_custom/switch.py b/custom_components/tesla_custom/switch.py index 8cde2890..55e2c684 100644 --- a/custom_components/tesla_custom/switch.py +++ b/custom_components/tesla_custom/switch.py @@ -43,9 +43,9 @@ def __init__( coordinator: TeslaDataUpdateCoordinator, ) -> None: """Initialize heated steering wheel entity.""" - super().__init__(car, coordinator) # Entity is disabled for cars with variable heated steering wheel. self._enabled_by_default = car.get_heated_steering_wheel_level() is not None + super().__init__(car, coordinator) @property def available(self) -> bool: @@ -131,9 +131,9 @@ def __init__( coordinator: TeslaDataUpdateCoordinator, ) -> None: """Initialize sentry mode entity.""" - super().__init__(car, coordinator) # Entity is only enabled upon first install if sentry mode is available - self._enabled_by_default = self._car.sentry_mode_available + self._enabled_by_default = car.sentry_mode_available + super().__init__(car, coordinator) @property def available(self) -> bool: diff --git a/custom_components/tesla_custom/text.py b/custom_components/tesla_custom/text.py index bebd5f1b..b30ca83f 100644 --- a/custom_components/tesla_custom/text.py +++ b/custom_components/tesla_custom/text.py @@ -41,9 +41,9 @@ def __init__( teslamate: TeslaMate, ) -> None: """Initialize charge limit entity.""" - super().__init__(car, coordinator) self.teslamate = teslamate self._state = None + super().__init__(car, coordinator) async def async_set_value(self, value: str) -> None: """Update charge limit."""