Add lamp capability to SmartThings (#144918)

This commit is contained in:
Joost Lekkerkerker 2025-05-16 10:36:58 +02:00 committed by GitHub
parent 3de740ed1e
commit e76b483067
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 199 additions and 4 deletions

View File

@ -41,6 +41,13 @@
"stop": "mdi:stop" "stop": "mdi:stop"
} }
}, },
"lamp": {
"default": "mdi:lightbulb",
"state": {
"on": "mdi:lightbulb-on",
"off": "mdi:lightbulb-off"
}
},
"detergent_amount": { "detergent_amount": {
"default": "mdi:car-coolant-level" "default": "mdi:car-coolant-level"
}, },

View File

@ -16,6 +16,10 @@ from . import FullDevice, SmartThingsConfigEntry
from .const import MAIN from .const import MAIN
from .entity import SmartThingsEntity from .entity import SmartThingsEntity
LAMP_TO_HA = {
"extraHigh": "extra_high",
}
@dataclass(frozen=True, kw_only=True) @dataclass(frozen=True, kw_only=True)
class SmartThingsSelectDescription(SelectEntityDescription): class SmartThingsSelectDescription(SelectEntityDescription):
@ -26,6 +30,7 @@ class SmartThingsSelectDescription(SelectEntityDescription):
options_attribute: Attribute options_attribute: Attribute
status_attribute: Attribute status_attribute: Attribute
command: Command command: Command
options_map: dict[str, str] | None = None
default_options: list[str] | None = None default_options: list[str] | None = None
@ -75,6 +80,15 @@ CAPABILITIES_TO_SELECT: dict[Capability | str, SmartThingsSelectDescription] = {
command=Command.SET_AMOUNT, command=Command.SET_AMOUNT,
entity_category=EntityCategory.CONFIG, entity_category=EntityCategory.CONFIG,
), ),
Capability.SAMSUNG_CE_LAMP: SmartThingsSelectDescription(
key=Capability.SAMSUNG_CE_LAMP,
translation_key="lamp",
options_attribute=Attribute.SUPPORTED_BRIGHTNESS_LEVEL,
status_attribute=Attribute.BRIGHTNESS_LEVEL,
command=Command.SET_BRIGHTNESS_LEVEL,
options_map=LAMP_TO_HA,
entity_category=EntityCategory.CONFIG,
),
} }
@ -117,20 +131,29 @@ class SmartThingsSelectEntity(SmartThingsEntity, SelectEntity):
@property @property
def options(self) -> list[str]: def options(self) -> list[str]:
"""Return the list of options.""" """Return the list of options."""
return ( options: list[str] = (
self.get_attribute_value( self.get_attribute_value(
self.entity_description.key, self.entity_description.options_attribute self.entity_description.key, self.entity_description.options_attribute
) )
or self.entity_description.default_options or self.entity_description.default_options
or [] or []
) )
if self.entity_description.options_map:
options = [
self.entity_description.options_map.get(option, option)
for option in options
]
return options
@property @property
def current_option(self) -> str | None: def current_option(self) -> str | None:
"""Return the current option.""" """Return the current option."""
return self.get_attribute_value( option = self.get_attribute_value(
self.entity_description.key, self.entity_description.status_attribute self.entity_description.key, self.entity_description.status_attribute
) )
if self.entity_description.options_map:
option = self.entity_description.options_map.get(option)
return option
async def async_select_option(self, option: str) -> None: async def async_select_option(self, option: str) -> None:
"""Select an option.""" """Select an option."""
@ -144,6 +167,15 @@ class SmartThingsSelectEntity(SmartThingsEntity, SelectEntity):
raise ServiceValidationError( raise ServiceValidationError(
"Can only be updated when remote control is enabled" "Can only be updated when remote control is enabled"
) )
if self.entity_description.options_map:
option = next(
(
key
for key, value in self.entity_description.options_map.items()
if value == option
),
option,
)
await self.execute_device_command( await self.execute_device_command(
self.entity_description.key, self.entity_description.key,
self.entity_description.command, self.entity_description.command,

View File

@ -115,6 +115,17 @@
"stop": "[%key:common::state::stopped%]" "stop": "[%key:common::state::stopped%]"
} }
}, },
"lamp": {
"name": "Lamp",
"state": {
"off": "[%key:common::state::off%]",
"on": "[%key:common::state::on%]",
"low": "Low",
"mid": "Mid",
"high": "High",
"extra_high": "Extra high"
}
},
"detergent_amount": { "detergent_amount": {
"name": "Detergent dispense amount", "name": "Detergent dispense amount",
"state": { "state": {

View File

@ -669,11 +669,11 @@
}, },
"samsungce.lamp": { "samsungce.lamp": {
"brightnessLevel": { "brightnessLevel": {
"value": "off", "value": "extraHigh",
"timestamp": "2025-03-13T21:23:27.659Z" "timestamp": "2025-03-13T21:23:27.659Z"
}, },
"supportedBrightnessLevel": { "supportedBrightnessLevel": {
"value": ["off", "high"], "value": ["off", "extraHigh"],
"timestamp": "2025-03-13T21:23:27.659Z" "timestamp": "2025-03-13T21:23:27.659Z"
} }
}, },

View File

@ -1,4 +1,116 @@
# serializer version: 1 # serializer version: 1
# name: test_all_entities[da_ks_oven_01061][select.oven_lamp-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': dict({
'options': list([
'off',
'high',
]),
}),
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'select',
'entity_category': <EntityCategory.CONFIG: 'config'>,
'entity_id': 'select.oven_lamp',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': None,
'original_icon': None,
'original_name': 'Lamp',
'platform': 'smartthings',
'previous_unique_id': None,
'supported_features': 0,
'translation_key': 'lamp',
'unique_id': '9447959a-0dfa-6b27-d40d-650da525c53f_main_samsungce.lamp_brightnessLevel_brightnessLevel',
'unit_of_measurement': None,
})
# ---
# name: test_all_entities[da_ks_oven_01061][select.oven_lamp-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'friendly_name': 'Oven Lamp',
'options': list([
'off',
'high',
]),
}),
'context': <ANY>,
'entity_id': 'select.oven_lamp',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'unknown',
})
# ---
# name: test_all_entities[da_ks_range_0101x][select.vulcan_lamp-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': dict({
'options': list([
'off',
'extra_high',
]),
}),
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'select',
'entity_category': <EntityCategory.CONFIG: 'config'>,
'entity_id': 'select.vulcan_lamp',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': None,
'original_icon': None,
'original_name': 'Lamp',
'platform': 'smartthings',
'previous_unique_id': None,
'supported_features': 0,
'translation_key': 'lamp',
'unique_id': '2c3cbaa0-1899-5ddc-7b58-9d657bd48f18_main_samsungce.lamp_brightnessLevel_brightnessLevel',
'unit_of_measurement': None,
})
# ---
# name: test_all_entities[da_ks_range_0101x][select.vulcan_lamp-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'friendly_name': 'Vulcan Lamp',
'options': list([
'off',
'extra_high',
]),
}),
'context': <ANY>,
'entity_id': 'select.vulcan_lamp',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'extra_high',
})
# ---
# name: test_all_entities[da_wm_dw_000001][select.dishwasher-entry] # name: test_all_entities[da_wm_dw_000001][select.dishwasher-entry]
EntityRegistryEntrySnapshot({ EntityRegistryEntrySnapshot({
'aliases': set({ 'aliases': set({

View File

@ -9,6 +9,7 @@ from syrupy import SnapshotAssertion
from homeassistant.components.select import ( from homeassistant.components.select import (
ATTR_OPTION, ATTR_OPTION,
ATTR_OPTIONS,
DOMAIN as SELECT_DOMAIN, DOMAIN as SELECT_DOMAIN,
SERVICE_SELECT_OPTION, SERVICE_SELECT_OPTION,
) )
@ -95,6 +96,38 @@ async def test_select_option(
) )
@pytest.mark.parametrize("device_fixture", ["da_ks_range_0101x"])
async def test_select_option_map(
hass: HomeAssistant,
devices: AsyncMock,
mock_config_entry: MockConfigEntry,
) -> None:
"""Test state update."""
await setup_integration(hass, mock_config_entry)
state = hass.states.get("select.vulcan_lamp")
assert state
assert state.state == "extra_high"
assert state.attributes[ATTR_OPTIONS] == [
"off",
"extra_high",
]
await hass.services.async_call(
SELECT_DOMAIN,
SERVICE_SELECT_OPTION,
{ATTR_ENTITY_ID: "select.vulcan_lamp", ATTR_OPTION: "extra_high"},
blocking=True,
)
devices.execute_device_command.assert_called_once_with(
"2c3cbaa0-1899-5ddc-7b58-9d657bd48f18",
Capability.SAMSUNG_CE_LAMP,
Command.SET_BRIGHTNESS_LEVEL,
MAIN,
argument="extraHigh",
)
@pytest.mark.parametrize("device_fixture", ["da_wm_wd_000001"]) @pytest.mark.parametrize("device_fixture", ["da_wm_wd_000001"])
async def test_select_option_without_remote_control( async def test_select_option_without_remote_control(
hass: HomeAssistant, hass: HomeAssistant,