mirror of
https://github.com/home-assistant/core.git
synced 2025-07-19 11:17:21 +00:00
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:
parent
7e299c2142
commit
da29b4ef16
@ -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."""
|
||||||
|
|
||||||
|
@ -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": {
|
||||||
|
@ -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',
|
||||||
|
})
|
||||||
|
# ---
|
||||||
|
@ -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,
|
||||||
|
)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user