Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: reduce code needed to construct entities #672

Merged
merged 3 commits into from
Jul 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading