diff --git a/homeassistant/components/switchbot_cloud/const.py b/homeassistant/components/switchbot_cloud/const.py index 15e958b4777..809a289a353 100644 --- a/homeassistant/components/switchbot_cloud/const.py +++ b/homeassistant/components/switchbot_cloud/const.py @@ -61,3 +61,25 @@ class Humidifier2Mode(Enum): def get_modes(cls) -> list[str]: """Return a list of available humidifier2 modes as lowercase strings.""" return [mode.name.lower() for mode in cls] + + +class SwitchbotCloudDeviceLockState(Enum): + """Lock State.""" + + LOCKED = "locked" + UNLOCKED = "unlocked" + LOCKING = "locking" + UNLOCKING = "unlocking" + JAMMED = "jammed" + LATCH_BOLT_LOCKED = "latchBoltLocked" + HALF_LOCKED = "halfLocked" + + @classmethod + def get_states(cls) -> list[SwitchbotCloudDeviceLockState]: + """Get lock states.""" + return list(cls) + + @classmethod + def get_values(cls) -> list[str]: + """Get lock value.""" + return [mode.value for mode in cls] diff --git a/homeassistant/components/switchbot_cloud/sensor.py b/homeassistant/components/switchbot_cloud/sensor.py index b6497572266..2b3d7c3e8f2 100644 --- a/homeassistant/components/switchbot_cloud/sensor.py +++ b/homeassistant/components/switchbot_cloud/sensor.py @@ -26,7 +26,7 @@ from homeassistant.helpers.device_registry import DeviceInfo from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback from . import SwitchbotCloudConfigEntry -from .const import DOMAIN +from .const import DOMAIN, SwitchbotCloudDeviceLockState from .coordinator import SwitchBotCoordinator from .entity import SwitchBotCloudEntity @@ -47,6 +47,8 @@ RELAY_SWITCH_2PM_SENSOR_TYPE_VOLTAGE = "Voltage" RELAY_SWITCH_2PM_SENSOR_TYPE_CURRENT = "ElectricCurrent" RELAY_SWITCH_2PM_SENSOR_TYPE_ELECTRICITY = "UsedElectricity" +LOCK_SENSOR_TYPE_LOCK_STATE = "lockState" + @dataclass(frozen=True, kw_only=True) class SwitchbotCloudSensorEntityDescription(SensorEntityDescription): @@ -165,6 +167,21 @@ LIGHTLEVEL_DESCRIPTION = SwitchbotCloudSensorEntityDescription( state_class=SensorStateClass.MEASUREMENT, ) + +LOCK_SENSOR_TYPE_LOCK_STATE_DESCRIPTION = SwitchbotCloudSensorEntityDescription( + key=LOCK_SENSOR_TYPE_LOCK_STATE, + device_class=SensorDeviceClass.ENUM, + translation_key="lock_state", + options=[ + value.name.lower() for value in SwitchbotCloudDeviceLockState.get_states() + ], + value_fn=lambda value: ( + SwitchbotCloudDeviceLockState(value).name.lower() + if value in SwitchbotCloudDeviceLockState.get_values() + else None + ), +) + SENSOR_DESCRIPTIONS_BY_DEVICE_TYPES = { "Bot": (BATTERY_DESCRIPTION,), "Battery Circulator Fan": (BATTERY_DESCRIPTION,), @@ -224,7 +241,10 @@ SENSOR_DESCRIPTIONS_BY_DEVICE_TYPES = { "Smart Lock": (BATTERY_DESCRIPTION,), "Smart Lock Lite": (BATTERY_DESCRIPTION,), "Smart Lock Pro": (BATTERY_DESCRIPTION,), - "Smart Lock Ultra": (BATTERY_DESCRIPTION,), + "Smart Lock Ultra": ( + BATTERY_DESCRIPTION, + LOCK_SENSOR_TYPE_LOCK_STATE_DESCRIPTION, + ), "Smart Lock Vision": (BATTERY_DESCRIPTION,), "Smart Lock Vision Pro": (BATTERY_DESCRIPTION,), "Lock Vision": (BATTERY_DESCRIPTION,), @@ -314,7 +334,6 @@ class SwitchBotCloudSensor(SwitchBotCloudEntity, SensorEntity): if not self.coordinator.data: return value = self.coordinator.data.get(self.entity_description.key) - self._attr_native_value = self.entity_description.value_fn(value) diff --git a/homeassistant/components/switchbot_cloud/strings.json b/homeassistant/components/switchbot_cloud/strings.json index 6883efff030..2bd4ff41bcc 100644 --- a/homeassistant/components/switchbot_cloud/strings.json +++ b/homeassistant/components/switchbot_cloud/strings.json @@ -76,6 +76,18 @@ "sensor": { "light_level": { "name": "Light level" + }, + "lock_state": { + "name": "Lock state", + "state": { + "half_locked": "Half locked", + "jammed": "Jammed", + "latch_bolt_locked": "Latch bolt locked", + "locked": "[%key:common::state::locked%]", + "locking": "Locking", + "unlocked": "[%key:common::state::unlocked%]", + "unlocking": "Unlocking" + } } } } diff --git a/tests/components/switchbot_cloud/__init__.py b/tests/components/switchbot_cloud/__init__.py index 6ad74cf9cb4..43cb93cc4fb 100644 --- a/tests/components/switchbot_cloud/__init__.py +++ b/tests/components/switchbot_cloud/__init__.py @@ -113,3 +113,11 @@ HUMIDIFIER2_INFO = Device( deviceType="Humidifier2", hubDeviceId="test-hub-id", ) + +LOCK_ULTRA_INFO = Device( + version="V1.0", + deviceId="lock-id-1", + deviceName="Lock Ultra", + deviceType="Smart Lock Ultra", + hubDeviceId="test-hub-id", +) diff --git a/tests/components/switchbot_cloud/test_lock.py b/tests/components/switchbot_cloud/test_lock.py index dfafda4110f..91ddb124dc0 100644 --- a/tests/components/switchbot_cloud/test_lock.py +++ b/tests/components/switchbot_cloud/test_lock.py @@ -2,6 +2,7 @@ from unittest.mock import patch +import pytest from switchbot_api import Device from homeassistant.components.lock import DOMAIN as LOCK_DOMAIN, LockState @@ -18,14 +19,28 @@ from homeassistant.core import HomeAssistant from . import configure_integration -async def test_lock(hass: HomeAssistant, mock_list_devices, mock_get_status) -> None: +@pytest.mark.parametrize( + ("device_info", "test_index"), + [ + ("Smart Lock", 0), + ("Smart Lock Lite", 1), + ("Smart Lock Pro", 2), + ("Smart Lock Ultra", 3), + ("Lock Vision", 4), + ("Lock Vision Pro", 5), + ("Smart Lock Pro Wifi", 6), + ], +) +async def test_lock( + hass: HomeAssistant, mock_list_devices, mock_get_status, device_info, test_index +) -> None: """Test locking and unlocking.""" mock_list_devices.return_value = [ Device( version="V1.0", deviceId="lock-id-1", deviceName="lock-1", - deviceType="Smart Lock", + deviceType=device_info, hubDeviceId="test-hub-id", ), ] @@ -52,16 +67,27 @@ async def test_lock(hass: HomeAssistant, mock_list_devices, mock_get_status) -> assert hass.states.get(lock_id).state == LockState.LOCKED +@pytest.mark.parametrize( + ("device_info", "test_index"), + [ + ("Smart Lock", 0), + ("Smart Lock Pro", 1), + ("Smart Lock Ultra", 2), + ("Lock Vision", 3), + ("Lock Vision Pro", 4), + ("Smart Lock Pro Wifi", 5), + ], +) async def test_lock_open( - hass: HomeAssistant, mock_list_devices, mock_get_status + hass: HomeAssistant, mock_list_devices, mock_get_status, device_info, test_index ) -> None: - """Test lock open.""" + """Test locking and unlocking.""" mock_list_devices.return_value = [ Device( version="V1.0", deviceId="lock-id-1", deviceName="lock-1", - deviceType="Smart Lock Pro", + deviceType=device_info, hubDeviceId="test-hub-id", ), ] diff --git a/tests/components/switchbot_cloud/test_sensor.py b/tests/components/switchbot_cloud/test_sensor.py index 78eec135ed5..38d03c64e0a 100644 --- a/tests/components/switchbot_cloud/test_sensor.py +++ b/tests/components/switchbot_cloud/test_sensor.py @@ -14,6 +14,7 @@ from homeassistant.helpers import entity_registry as er from . import ( CONTACT_SENSOR_INFO, HUB3_INFO, + LOCK_ULTRA_INFO, METER_INFO, MOTION_SENSOR_INFO, WATER_DETECTOR_INFO, @@ -32,6 +33,7 @@ from tests.common import snapshot_platform (HUB3_INFO, 3), (MOTION_SENSOR_INFO, 4), (WATER_DETECTOR_INFO, 5), + (LOCK_ULTRA_INFO, 5), ], ) async def test_meter(