Skip to content

Commit

Permalink
feat: add scheduled departure and charging (#441)
Browse files Browse the repository at this point in the history
closes #164
  • Loading branch information
InTheDaylight14 authored Dec 20, 2022
1 parent 43f7169 commit f555131
Show file tree
Hide file tree
Showing 3 changed files with 151 additions and 5 deletions.
74 changes: 73 additions & 1 deletion custom_components/tesla_custom/binary_sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ async def async_setup_entry(hass: HomeAssistant, config_entry, async_add_entitie
entities.append(TeslaCarChargerConnection(hass, car, coordinator))
entities.append(TeslaCarCharging(hass, car, coordinator))
entities.append(TeslaCarDoors(hass, car, coordinator))
entities.append(TeslaCarScheduledCharging(hass, car, coordinator))
entities.append(TeslaCarScheduledDeparture(hass, car, coordinator))

for energysite in energysites.values():
if energysite.resource_type == RESOURCE_TYPE_BATTERY:
Expand Down Expand Up @@ -226,7 +228,12 @@ def __init__(
@property
def is_on(self):
"""Return True if a car door is open."""
return self._car.door_df or self._car.door_dr or self._car.door_pf or self._car.door_pr
return (
self._car.door_df
or self._car.door_dr
or self._car.door_pf
or self._car.door_pr
)

@property
def extra_state_attributes(self):
Expand All @@ -243,3 +250,68 @@ def _open_or_closed(self, door):
if door:
return "Open"
return "Closed"


class TeslaCarScheduledCharging(TeslaCarEntity, BinarySensorEntity):
"""Representation of a Tesla car scheduled charging binary sensor."""

def __init__(
self,
hass: HomeAssistant,
car: TeslaCar,
coordinator: TeslaDataUpdateCoordinator,
) -> None:
"""Initialize scheduled charging entity."""
super().__init__(hass, car, coordinator)
self.type = "scheduled charging"
self._attr_icon = "mdi:calendar-plus"
self._attr_device_class = None

@property
def is_on(self):
"""Return True if scheduled charging enebaled."""
if self._car.scheduled_charging_mode == "StartAt":
return True
return False

@property
def extra_state_attributes(self):
"""Return device state attributes."""
return {
"Scheduled charging time": self._car.scheduled_charging_start_time_app,
}


class TeslaCarScheduledDeparture(TeslaCarEntity, BinarySensorEntity):
"""Representation of a Tesla car scheduled departure binary sensor."""

def __init__(
self,
hass: HomeAssistant,
car: TeslaCar,
coordinator: TeslaDataUpdateCoordinator,
) -> None:
"""Initialize scheduled departure entity."""
super().__init__(hass, car, coordinator)
self.type = "scheduled departure"
self._attr_icon = "mdi:calendar-plus"
self._attr_device_class = None

@property
def is_on(self):
"""Return True if scheduled departure enebaled."""
if self._car.scheduled_charging_mode == "DepartBy":
return True
return False

@property
def extra_state_attributes(self):
"""Return device state attributes."""
return {
"Departure time": self._car.scheduled_departure_time_minutes,
"Preconditioning enabled": self._car.is_preconditioning_enabled,
"Preconditioning weekdays only": self._car.is_preconditioning_weekday_only,
"Off peak charging enabled": self._car.is_off_peak_charging_enabled,
"Off peak charging weekdays only": self._car.is_off_peak_charging_weekday_only,
"End off peak time": self._car.off_peak_hours_end_time,
}
2 changes: 1 addition & 1 deletion tests/mock_data/car.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@
"scheduled_charging_mode": "DepartBy",
"scheduled_charging_pending": False,
"scheduled_charging_start_time": None,
"scheduled_charging_start_time_app": 0,
"scheduled_charging_start_time_app": 480,
"scheduled_departure_time": 1661515200,
"scheduled_departure_time_minutes": 300,
"supercharger_session_trip_planner": False,
Expand Down
80 changes: 77 additions & 3 deletions tests/test_binary_sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,12 @@ async def test_registry_entries(hass: HomeAssistant) -> None:
entry = entity_registry.async_get("binary_sensor.my_model_s_online")
assert entry.unique_id == f"{car_mock_data.VIN.lower()}_online"

entry = entity_registry.async_get("binary_sensor.my_model_s_scheduled_charging")
assert entry.unique_id == f"{car_mock_data.VIN.lower()}_scheduled_charging"

entry = entity_registry.async_get("binary_sensor.my_model_s_scheduled_departure")
assert entry.unique_id == f"{car_mock_data.VIN.lower()}_scheduled_departure"

entry = entity_registry.async_get("binary_sensor.battery_home_battery_charging")
assert entry.unique_id == "67890_battery_charging"

Expand Down Expand Up @@ -138,18 +144,86 @@ async def test_grid_status(hass: HomeAssistant) -> None:

assert state.attributes.get(ATTR_DEVICE_CLASS) == BinarySensorDeviceClass.POWER


async def test_car_doors(hass: HomeAssistant) -> None:
"""Tests car door is getting the correct value."""
await setup_platform(hass, BINARY_SENSOR_DOMAIN)

state = hass.states.get("binary_sensor.my_model_s_doors")
assert state.state == STATE_ON

assert (
state.attributes.get(ATTR_DEVICE_CLASS) == BinarySensorDeviceClass.DOOR
)
assert state.attributes.get(ATTR_DEVICE_CLASS) == BinarySensorDeviceClass.DOOR

assert state.attributes.get("Driver Front") == "Open"
assert state.attributes.get("Driver Rear") == "Closed"
assert state.attributes.get("Passenger Front") == "Closed"
assert state.attributes.get("Passenger Rear") == "Closed"


async def test_car_scheduled_charging(hass: HomeAssistant) -> None:
"""Tests scheduled charging is getting the correct value."""
await setup_platform(hass, BINARY_SENSOR_DOMAIN)

state = hass.states.get("binary_sensor.my_model_s_scheduled_charging")
assert state.state == STATE_OFF

assert (
state.attributes.get("Scheduled charging time")
== car_mock_data.VEHICLE_DATA["charge_state"][
"scheduled_charging_start_time_app"
]
)


async def test_car_scheduled_departure(hass: HomeAssistant) -> None:
"""Tests scheduled departure is getting the correct value."""
await setup_platform(hass, BINARY_SENSOR_DOMAIN)

state = hass.states.get("binary_sensor.my_model_s_scheduled_departure")
assert state.state == STATE_ON

assert (
state.attributes.get("Departure time")
== car_mock_data.VEHICLE_DATA["charge_state"][
"scheduled_departure_time_minutes"
]
)

assert (
state.attributes.get("Preconditioning enabled")
== car_mock_data.VEHICLE_DATA["charge_state"]["preconditioning_enabled"]
)

if (
car_mock_data.VEHICLE_DATA["charge_state"]["preconditioning_times"]
== "weekdays"
):
check_precondition_weekdays_only = True
else:
check_precondition_weekdays_only = False
assert (
state.attributes.get("Preconditioning weekdays only")
== check_precondition_weekdays_only
)

assert (
state.attributes.get("Off peak charging enabled")
== car_mock_data.VEHICLE_DATA["charge_state"]["off_peak_charging_enabled"]
)

if (
car_mock_data.VEHICLE_DATA["charge_state"]["off_peak_charging_times"]
== "weekdays"
):
check_off_peak_weekdays_only = True
else:
check_off_peak_weekdays_only = False
assert (
state.attributes.get("Off peak charging weekdays only")
== check_off_peak_weekdays_only
)

assert (
state.attributes.get("End off peak time")
== car_mock_data.VEHICLE_DATA["charge_state"]["off_peak_hours_end_time"]
)

0 comments on commit f555131

Please sign in to comment.