Skip to content

Commit

Permalink
fix: persist entities when reloaded while car is asleep (#365)
Browse files Browse the repository at this point in the history
Change behavior for auto creation of entities to create but disable until detected.

closes #293
  • Loading branch information
carleeno authored Nov 21, 2022
1 parent 00eeaa5 commit f0fc6e4
Show file tree
Hide file tree
Showing 8 changed files with 149 additions and 25 deletions.
10 changes: 8 additions & 2 deletions custom_components/tesla_custom/button.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,7 @@ async def async_setup_entry(hass: HomeAssistant, config_entry, async_add_entitie
entities.append(TeslaCarFlashLights(hass, car, coordinator))
entities.append(TeslaCarWakeUp(hass, car, coordinator))
entities.append(TeslaCarForceDataUpdate(hass, car, coordinator))
if car.homelink_device_count:
entities.append(TeslaCarTriggerHomelink(hass, car, coordinator))
entities.append(TeslaCarTriggerHomelink(hass, car, coordinator))

async_add_entities(entities, True)

Expand Down Expand Up @@ -132,6 +131,13 @@ def __init__(
super().__init__(hass, car, coordinator)
self.type = "homelink"
self._attr_icon = "mdi:garage"
# Entity is only enabled upon first install if garages have been paired to homelink
self._enabled_by_default = self._car.homelink_device_count

@property
def available(self) -> bool:
"""Return True if Homelink devices are nearby"""
return super().available and self._car.homelink_nearby

async def async_press(self):
"""Send the command."""
Expand Down
2 changes: 1 addition & 1 deletion custom_components/tesla_custom/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"documentation": "https://github.com/alandtse/tesla/wiki",
"issue_tracker": "https://github.com/alandtse/tesla/issues",
"requirements": [
"teslajsonpy==3.2.0"
"teslajsonpy==3.2.1"
],
"codeowners": [
"@alandtse"
Expand Down
20 changes: 16 additions & 4 deletions custom_components/tesla_custom/switch.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,8 @@ async def async_setup_entry(hass: HomeAssistant, config_entry, async_add_entitie
entities = []

for car in cars.values():
if car.steering_wheel_heater:
entities.append(TeslaCarHeatedSteeringWheel(hass, car, coordinator))
if car.sentry_mode_available:
entities.append(TeslaCarSentryMode(hass, car, coordinator))
entities.append(TeslaCarHeatedSteeringWheel(hass, car, coordinator))
entities.append(TeslaCarSentryMode(hass, car, coordinator))
entities.append(TeslaCarPolling(hass, car, coordinator))
entities.append(TeslaCarCharger(hass, car, coordinator))

Expand All @@ -44,6 +42,13 @@ def __init__(
super().__init__(hass, car, coordinator)
self.type = "heated steering"
self._attr_icon = "mdi:steering"
# Entity is only enabled upon first install if steering wheel heater is available
self._enabled_by_default = self._car.steering_wheel_heater

@property
def available(self) -> bool:
"""Return True if steering wheel heater is available"""
return super().available and self._car.steering_wheel_heater

@property
def is_on(self):
Expand Down Expand Up @@ -140,6 +145,13 @@ def __init__(
super().__init__(hass, car, coordinator)
self.type = "sentry mode"
self._attr_icon = "mdi:shield-car"
# Entity is only enabled upon first install if sentry mode is available
self._enabled_by_default = self._car.sentry_mode_available

@property
def available(self) -> bool:
"""Return True if sentry mode switch is available"""
return super().available and self._car.sentry_mode_available

@property
def is_on(self):
Expand Down
8 changes: 4 additions & 4 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ license = "Apache-2.0"

[tool.poetry.dependencies]
python = "^3.10"
teslajsonpy = "^3.2.0"
teslajsonpy = "^3.2.1"

[tool.poetry.dev-dependencies]
homeassistant = ">=2021.10.0"
Expand Down
38 changes: 37 additions & 1 deletion tests/mock_data/car.py
Original file line number Diff line number Diff line change
Expand Up @@ -260,5 +260,41 @@
"charge_state": None,
"gui_settings": None,
"vehicle_state": None,
"vehicle_config": None,
"vehicle_config": {
"can_accept_navigation_requests": True,
"can_actuate_trunks": True,
"car_special_type": "base",
"car_type": "models",
"charge_port_type": "US",
"dashcam_clip_save_supported": False,
"default_charge_to_max": False,
"driver_assist": "MonoCam",
"ece_restrictions": False,
"efficiency_package": "Default",
"eu_vehicle": False,
"exterior_color": "White",
"front_drive_unit": "NoneOrSmall",
"has_air_suspension": False,
"has_ludicrous_mode": False,
"has_seat_cooling": False,
"headlamp_type": "Hid",
"interior_trim_type": "AllBlack",
"motorized_charge_port": True,
"plg": True,
"pws": False,
"rear_drive_unit": "Small",
"rear_seat_heaters": 0,
"rear_seat_type": 1,
"rhd": False,
"roof_color": "Colored",
"seat_type": 1,
"spoiler_type": "None",
"sun_roof_installed": 0,
"third_row_seats": "None",
"timestamp": 1661641175269,
"trim_badging": "85d",
"use_range_badging": False,
"utc_offset": -25200,
"wheel_type": "Base19",
},
}
59 changes: 47 additions & 12 deletions tests/test_button.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,39 @@ async def test_registry_entries(hass: HomeAssistant) -> None:
assert entry.unique_id == f"{car_mock_data.VIN.lower()}_homelink"


async def test_enabled_by_default(hass: HomeAssistant) -> None:
"""Tests devices are enabled by default."""
await setup_platform(hass, BUTTON_DOMAIN)
entity_registry = er.async_get(hass)

entry = entity_registry.async_get("button.my_model_s_horn")
assert not entry.disabled

entry = entity_registry.async_get("button.my_model_s_flash_lights")
assert not entry.disabled

entry = entity_registry.async_get("button.my_model_s_wake_up")
assert not entry.disabled

entry = entity_registry.async_get("button.my_model_s_force_data_update")
assert not entry.disabled

# Default mock data has homelink enabled
entry = entity_registry.async_get("button.my_model_s_homelink")
assert not entry.disabled


async def test_disabled_by_default(hass: HomeAssistant) -> None:
"""Tests devices are disabled by default when appropriate."""
# No garages paired, it should be disabled by default.
car_mock_data.VEHICLE_DATA["vehicle_state"]["homelink_device_count"] = 0
await setup_platform(hass, BUTTON_DOMAIN)
entity_registry = er.async_get(hass)

entry = entity_registry.async_get("button.my_model_s_homelink")
assert entry.disabled


async def test_horn_press(hass: HomeAssistant) -> None:
"""Tests car horn button press."""
await setup_platform(hass, BUTTON_DOMAIN)
Expand Down Expand Up @@ -91,15 +124,17 @@ async def test_force_data_update_press(hass: HomeAssistant) -> None:
mock_force_data_update.assert_awaited_once_with(wake_if_asleep=True, force=True)


# async def test_trigger_homelink_press(hass: HomeAssistant) -> None:
# """Tests car trigger homelink button press."""
# await setup_platform(hass, BUTTON_DOMAIN)
# # Need a way to enable this device before running tests (disabled by default)
# with patch("teslajsonpy.car.TeslaCar.trigger_homelink") as mock_trigger_homelink:
# assert await hass.services.async_call(
# BUTTON_DOMAIN,
# "press",
# {ATTR_ENTITY_ID: "button.my_model_s_trigger_homelink"},
# blocking=True,
# )
# mock_trigger_homelink.assert_awaited_once()
async def test_trigger_homelink_press(hass: HomeAssistant) -> None:
"""Tests car trigger homelink button press."""
car_mock_data.VEHICLE_DATA["vehicle_state"]["homelink_device_count"] = 1
car_mock_data.VEHICLE_DATA["vehicle_state"]["homelink_nearby"] = True
await setup_platform(hass, BUTTON_DOMAIN)

with patch("teslajsonpy.car.TeslaCar.trigger_homelink") as mock_trigger_homelink:
assert await hass.services.async_call(
BUTTON_DOMAIN,
"press",
{ATTR_ENTITY_ID: "button.my_model_s_homelink"},
blocking=True,
)
mock_trigger_homelink.assert_awaited_once()
35 changes: 35 additions & 0 deletions tests/test_switch.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from .common import setup_platform
from .mock_data import car as car_mock_data


async def test_registry_entries(hass: HomeAssistant) -> None:
"""Tests devices are registered in the entity registry."""
await setup_platform(hass, SWITCH_DOMAIN)
Expand All @@ -27,8 +28,41 @@ async def test_registry_entries(hass: HomeAssistant) -> None:
assert entry.unique_id == f"{car_mock_data.VIN.lower()}_sentry_mode"


async def test_enabled_by_default(hass: HomeAssistant) -> None:
"""Tests devices are registered in the entity registry."""
await setup_platform(hass, SWITCH_DOMAIN)
entity_registry = er.async_get(hass)

entry = entity_registry.async_get("switch.my_model_s_heated_steering")
assert not entry.disabled

entry = entity_registry.async_get("switch.my_model_s_polling")
assert not entry.disabled

entry = entity_registry.async_get("switch.my_model_s_charger")
assert not entry.disabled

entry = entity_registry.async_get("switch.my_model_s_sentry_mode")
assert not entry.disabled


async def test_disabled_by_default(hass: HomeAssistant) -> None:
"""Tests devices are disabled by default when appropriate."""
car_mock_data.VEHICLE_DATA["climate_state"]["steering_wheel_heater"] = None
car_mock_data.VEHICLE_DATA["vehicle_state"]["sentry_mode_available"] = False
await setup_platform(hass, SWITCH_DOMAIN)
entity_registry = er.async_get(hass)

entry = entity_registry.async_get("switch.my_model_s_heated_steering")
assert entry.disabled

entry = entity_registry.async_get("switch.my_model_s_sentry_mode")
assert entry.disabled


async def test_heated_steering(hass: HomeAssistant) -> None:
"""Tests car heated steering switch."""
car_mock_data.VEHICLE_DATA["climate_state"]["steering_wheel_heater"] = False
await setup_platform(hass, SWITCH_DOMAIN)

with patch(
Expand Down Expand Up @@ -96,6 +130,7 @@ async def test_charger(hass: HomeAssistant) -> None:

async def test_sentry_mode(hass: HomeAssistant) -> None:
"""Tests car sentry mode switch."""
car_mock_data.VEHICLE_DATA["vehicle_state"]["sentry_mode_available"] = True
await setup_platform(hass, SWITCH_DOMAIN)

with patch("teslajsonpy.car.TeslaCar.set_sentry_mode") as mock_set_sentry_mode:
Expand Down

0 comments on commit f0fc6e4

Please sign in to comment.