Skip to content

Commit

Permalink
refactor: reduce code needed to construct entities (#672)
Browse files Browse the repository at this point in the history
  • Loading branch information
bdraco authored Jul 27, 2023
1 parent fe9050f commit f0b97ba
Show file tree
Hide file tree
Showing 6 changed files with 50 additions and 92 deletions.
118 changes: 38 additions & 80 deletions custom_components/tesla_custom/base.py
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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):
Expand All @@ -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
Expand All @@ -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."""
Expand All @@ -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,
)
6 changes: 3 additions & 3 deletions custom_components/tesla_custom/button.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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."""
Expand Down
4 changes: 2 additions & 2 deletions custom_components/tesla_custom/select.py
Original file line number Diff line number Diff line change
Expand Up @@ -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."""
Expand Down Expand Up @@ -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."""
Expand Down
6 changes: 3 additions & 3 deletions custom_components/tesla_custom/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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"
Expand All @@ -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:
Expand Down Expand Up @@ -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:
Expand Down
6 changes: 3 additions & 3 deletions custom_components/tesla_custom/switch.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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:
Expand Down
2 changes: 1 addition & 1 deletion custom_components/tesla_custom/text.py
Original file line number Diff line number Diff line change
Expand Up @@ -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."""
Expand Down

0 comments on commit f0b97ba

Please sign in to comment.