Add Speed Limit to Tessie lock platform (#106527)

* Add speed limit

* Make regex more readable

* Add tests

* Add test

* Ruff

* Remove extra line

* Update snapshot

* Remove bad snapshot
This commit is contained in:
Brett Adams 2024-02-04 07:21:19 +10:00 committed by GitHub
parent 7e299c2142
commit da29b4ef16
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 126 additions and 6 deletions

View File

@ -3,9 +3,15 @@ from __future__ import annotations
from typing import Any from typing import Any
from tessie_api import lock, open_unlock_charge_port, unlock from tessie_api import (
disable_speed_limit,
enable_speed_limit,
lock,
open_unlock_charge_port,
unlock,
)
from homeassistant.components.lock import LockEntity from homeassistant.components.lock import ATTR_CODE, LockEntity
from homeassistant.config_entries import ConfigEntry from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.exceptions import ServiceValidationError from homeassistant.exceptions import ServiceValidationError
@ -24,7 +30,7 @@ async def async_setup_entry(
async_add_entities( async_add_entities(
klass(vehicle.state_coordinator) klass(vehicle.state_coordinator)
for klass in (TessieLockEntity, TessieCableLockEntity) for klass in (TessieLockEntity, TessieCableLockEntity, TessieSpeedLimitEntity)
for vehicle in data for vehicle in data
) )
@ -55,6 +61,38 @@ class TessieLockEntity(TessieEntity, LockEntity):
self.set((self.key, False)) self.set((self.key, False))
class TessieSpeedLimitEntity(TessieEntity, LockEntity):
"""Speed Limit with PIN entity for Tessie."""
_attr_code_format = r"^\d\d\d\d$"
def __init__(
self,
coordinator: TessieStateUpdateCoordinator,
) -> None:
"""Initialize the sensor."""
super().__init__(coordinator, "vehicle_state_speed_limit_mode_active")
@property
def is_locked(self) -> bool | None:
"""Return the state of the Lock."""
return self._value
async def async_lock(self, **kwargs: Any) -> None:
"""Enable speed limit with pin."""
code: str | None = kwargs.get(ATTR_CODE)
if code:
await self.run(enable_speed_limit, pin=code)
self.set((self.key, True))
async def async_unlock(self, **kwargs: Any) -> None:
"""Disable speed limit with pin."""
code: str | None = kwargs.get(ATTR_CODE)
if code:
await self.run(disable_speed_limit, pin=code)
self.set((self.key, False))
class TessieCableLockEntity(TessieEntity, LockEntity): class TessieCableLockEntity(TessieEntity, LockEntity):
"""Cable Lock entity for Tessie.""" """Cable Lock entity for Tessie."""

View File

@ -59,6 +59,9 @@
}, },
"charge_state_charge_port_latch": { "charge_state_charge_port_latch": {
"name": "Charge cable lock" "name": "Charge cable lock"
},
"vehicle_state_speed_limit_mode_active": {
"name": "Speed limit"
} }
}, },
"media_player": { "media_player": {

View File

@ -87,3 +87,48 @@
'state': 'locked', 'state': 'locked',
}) })
# --- # ---
# name: test_locks[lock.test_speed_limit-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'lock',
'entity_category': None,
'entity_id': 'lock.test_speed_limit',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'name': None,
'options': dict({
}),
'original_device_class': None,
'original_icon': None,
'original_name': 'Speed limit',
'platform': 'tessie',
'previous_unique_id': None,
'supported_features': 0,
'translation_key': 'vehicle_state_speed_limit_mode_active',
'unique_id': 'VINVINVIN-vehicle_state_speed_limit_mode_active',
'unit_of_measurement': None,
})
# ---
# name: test_locks[lock.test_speed_limit-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'code_format': '^\\d\\d\\d\\d$',
'friendly_name': 'Test Speed limit',
'supported_features': <LockEntityFeature: 0>,
}),
'context': <ANY>,
'entity_id': 'lock.test_speed_limit',
'last_changed': <ANY>,
'last_updated': <ANY>,
'state': 'unlocked',
})
# ---

View File

@ -6,6 +6,7 @@ import pytest
from syrupy import SnapshotAssertion from syrupy import SnapshotAssertion
from homeassistant.components.lock import ( from homeassistant.components.lock import (
ATTR_CODE,
DOMAIN as LOCK_DOMAIN, DOMAIN as LOCK_DOMAIN,
SERVICE_LOCK, SERVICE_LOCK,
SERVICE_UNLOCK, SERVICE_UNLOCK,
@ -27,9 +28,8 @@ async def test_locks(
assert_entities(hass, entry.entry_id, entity_registry, snapshot) assert_entities(hass, entry.entry_id, entity_registry, snapshot)
entity_id = "lock.test_lock"
# Test lock set value functions # Test lock set value functions
entity_id = "lock.test_lock"
with patch("homeassistant.components.tessie.lock.lock") as mock_run: with patch("homeassistant.components.tessie.lock.lock") as mock_run:
await hass.services.async_call( await hass.services.async_call(
LOCK_DOMAIN, LOCK_DOMAIN,
@ -47,8 +47,8 @@ async def test_locks(
{ATTR_ENTITY_ID: [entity_id]}, {ATTR_ENTITY_ID: [entity_id]},
blocking=True, blocking=True,
) )
mock_run.assert_called_once() mock_run.assert_called_once()
assert hass.states.get(entity_id).state == STATE_UNLOCKED
# Test charge cable lock set value functions # Test charge cable lock set value functions
entity_id = "lock.test_charge_cable_lock" entity_id = "lock.test_charge_cable_lock"
@ -71,3 +71,37 @@ async def test_locks(
) )
assert hass.states.get(entity_id).state == STATE_UNLOCKED assert hass.states.get(entity_id).state == STATE_UNLOCKED
mock_run.assert_called_once() mock_run.assert_called_once()
# Test lock set value functions
entity_id = "lock.test_speed_limit"
with patch(
"homeassistant.components.tessie.lock.enable_speed_limit"
) as mock_enable_speed_limit:
await hass.services.async_call(
LOCK_DOMAIN,
SERVICE_LOCK,
{ATTR_ENTITY_ID: [entity_id], ATTR_CODE: "1234"},
blocking=True,
)
assert hass.states.get(entity_id).state == STATE_LOCKED
mock_enable_speed_limit.assert_called_once()
with patch(
"homeassistant.components.tessie.lock.disable_speed_limit"
) as mock_disable_speed_limit:
await hass.services.async_call(
LOCK_DOMAIN,
SERVICE_UNLOCK,
{ATTR_ENTITY_ID: [entity_id], ATTR_CODE: "1234"},
blocking=True,
)
assert hass.states.get(entity_id).state == STATE_UNLOCKED
mock_disable_speed_limit.assert_called_once()
with pytest.raises(ServiceValidationError):
await hass.services.async_call(
LOCK_DOMAIN,
SERVICE_UNLOCK,
{ATTR_ENTITY_ID: [entity_id], ATTR_CODE: "abc"},
blocking=True,
)