Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 41 additions & 2 deletions homeassistant/components/homeassistant/scene.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,17 @@
State,
callback,
)
from homeassistant.exceptions import HomeAssistantError
from homeassistant.exceptions import HomeAssistantError, ServiceValidationError
from homeassistant.helpers import (
config_per_platform,
config_validation as cv,
entity_platform,
)
from homeassistant.helpers.entity_platform import AddEntitiesCallback, EntityPlatform
from homeassistant.helpers.service import async_register_admin_service
from homeassistant.helpers.service import (
async_extract_entity_ids,
async_register_admin_service,
)
from homeassistant.helpers.state import async_reproduce_state
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
from homeassistant.loader import async_get_integration
Expand Down Expand Up @@ -125,6 +128,7 @@ def _ensure_no_intersection(value: dict[str, Any]) -> dict[str, Any]:

SERVICE_APPLY = "apply"
SERVICE_CREATE = "create"
SERVICE_DELETE = "delete"

_LOGGER = logging.getLogger(__name__)

Expand Down Expand Up @@ -273,6 +277,41 @@ async def create_service(call: ServiceCall) -> None:
SCENE_DOMAIN, SERVICE_CREATE, create_service, CREATE_SCENE_SCHEMA
)

async def delete_service(call: ServiceCall) -> None:
"""Delete a dynamically created scene."""
entity_ids = await async_extract_entity_ids(hass, call)

for entity_id in entity_ids:
scene = platform.entities.get(entity_id)
if scene is None:
raise ServiceValidationError(
f"{entity_id} is not a valid scene entity_id",
translation_domain=SCENE_DOMAIN,
translation_key="entity_not_scene",
translation_placeholders={
"entity_id": entity_id,
},
)
assert isinstance(scene, HomeAssistantScene)
if not scene.from_service:
raise ServiceValidationError(
f"The scene {entity_id} is not created with service `scene.create`",
translation_domain=SCENE_DOMAIN,
translation_key="entity_not_dynamically_created",
translation_placeholders={
"entity_id": entity_id,
},
)

await platform.async_remove_entity(entity_id)

hass.services.async_register(
Comment thread
tetele marked this conversation as resolved.
SCENE_DOMAIN,
SERVICE_DELETE,
delete_service,
cv.make_entity_service_schema({}),
)


def _process_scenes_config(
hass: HomeAssistant, async_add_entities: AddEntitiesCallback, config: dict[str, Any]
Expand Down
6 changes: 6 additions & 0 deletions homeassistant/components/scene/services.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -54,3 +54,9 @@ create:
selector:
entity:
multiple: true

delete:
Comment thread
tetele marked this conversation as resolved.
target:
entity:
- integration: homeassistant
domain: scene
12 changes: 12 additions & 0 deletions homeassistant/components/scene/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,18 @@
"description": "List of entities to be included in the snapshot. By taking a snapshot, you record the current state of those entities. If you do not want to use the current state of all your entities for this scene, you can combine the `snapshot_entities` with `entities`."
}
}
},
"delete": {
Comment thread
tetele marked this conversation as resolved.
"name": "Delete",
"description": "Deletes a dynamically created scene."
}
},
"exceptions": {
"entity_not_scene": {
"message": "{entity_id} is not a valid scene entity_id."
},
"entity_not_dynamically_created": {
"message": "The scene {entity_id} is not created with service `scene.create`."
}
}
}
60 changes: 60 additions & 0 deletions tests/components/homeassistant/test_scene.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from homeassistant.components.homeassistant.scene import EVENT_SCENE_RELOADED
from homeassistant.const import STATE_UNKNOWN
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import ServiceValidationError
from homeassistant.setup import async_setup_component

from tests.common import async_capture_events, async_mock_service
Expand Down Expand Up @@ -164,6 +165,65 @@ async def test_create_service(
assert scene.attributes.get("entity_id") == ["light.kitchen"]


async def test_delete_service(
hass: HomeAssistant, caplog: pytest.LogCaptureFixture
) -> None:
"""Test the delete service."""
assert await async_setup_component(
hass,
"scene",
{"scene": {"name": "hallo_2", "entities": {"light.kitchen": "on"}}},
)

await hass.services.async_call(
"scene",
"create",
{
"scene_id": "hallo",
"entities": {"light.bed_light": {"state": "on", "brightness": 50}},
},
blocking=True,
)
await hass.async_block_till_done()

with pytest.raises(ServiceValidationError):
await hass.services.async_call(
"scene",
"delete",
{
"entity_id": "scene.hallo_3",
},
blocking=True,
)
await hass.async_block_till_done()

with pytest.raises(ServiceValidationError):
await hass.services.async_call(
"scene",
"delete",
{
"entity_id": "scene.hallo_2",
},
blocking=True,
)
await hass.async_block_till_done()
assert hass.states.get("scene.hallo_2") is not None

assert hass.states.get("scene.hallo") is not None

await hass.services.async_call(
Comment thread
tetele marked this conversation as resolved.
"scene",
"delete",
{
"entity_id": "scene.hallo",
},
blocking=True,
)
await hass.async_block_till_done()

assert hass.states.get("state.hallo") is None


async def test_snapshot_service(
hass: HomeAssistant, caplog: pytest.LogCaptureFixture
) -> None:
Expand Down