Skip to content

Scene

scene

scene domain implementation.

Scenes apply a pre-defined set of entity states in one shot. They are fire-and-forget: there is no turn_off counterpart.

Domain-level operations

Beyond per-entity actions, the scene domain exposes two collection-level operations on the SceneAccessor (returned by ha.scene):

  • await ha.scene.create(scene_id, entities, *, snapshot_entities=None) — create (or update) a runtime scene helper, returning a Scene.
  • await ha.scene.apply(entities, *, transition=None) — apply a state combination without persisting it.

Per-entity access still works through the usual ha.scene("name") / ha.scene["name"] syntax.

SPEC module-attribute

SPEC: DomainSpec[Scene] = register_domain(DomainSpec(name='scene', entity_cls=Scene, accessor_cls=SceneAccessor))

The DomainSpec registered with the shared DomainRegistry.

Scene

Bases: Entity

A Home Assistant scene entity.

Activating a scene applies a set of pre-defined entity states. The entity state is the ISO-8601 timestamp of the last activation (or "unavailable" / "unknown" when not applicable).

Source code in src/haclient/domains/scene.py
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
class Scene(Entity):
    """A Home Assistant scene entity.

    Activating a scene applies a set of pre-defined entity states.  The
    entity ``state`` is the ISO-8601 timestamp of the last activation
    (or ``"unavailable"`` / ``"unknown"`` when not applicable).
    """

    domain = "scene"

    # -- State properties ---------------------------------------------

    @property
    def last_activated(self) -> str | None:
        """ISO-8601 timestamp of the last activation, or ``None``."""
        if self.state in ("unavailable", "unknown", None):
            return None
        return self.state

    @property
    def entity_ids(self) -> list[str]:
        """Entity IDs controlled by this scene."""
        val = self.attributes.get("entity_id")
        if isinstance(val, list):
            return [str(v) for v in val]
        return []

    @property
    def name(self) -> str | None:
        """Human-readable name of the scene.

        Returns
        -------
        str or None
            The HA ``friendly_name`` attribute, or ``None`` when the
            entity does not advertise one. Note that this property
            deliberately does not return the scene's ``entity_id``
            or object-id slug.
        """
        val = self.attributes.get("friendly_name")
        return str(val) if val is not None else None

    @property
    def icon(self) -> str | None:
        """Icon identifier for the scene.

        Returns
        -------
        str or None
            The raw HA ``icon`` attribute, typically a Material Design
            Icons identifier of the form ``"mdi:<name>"``. ``None`` when
            the entity does not advertise an icon.
        """
        val = self.attributes.get("icon")
        return str(val) if val is not None else None

    # -- Actions ------------------------------------------------------

    async def activate(self, *, transition: float | None = None) -> None:
        """Activate the scene.

        Parameters
        ----------
        transition : float or None, optional
            Seconds over which entities supporting transitions should
            move to their scene state.
        """
        data: dict[str, Any] | None = None
        if transition is not None:
            data = {"transition": transition}
        await self._call_service("turn_on", data)

    async def delete(self) -> None:
        """Delete this dynamically-created scene.

        Invokes the ``scene.delete`` Home Assistant service. This is
        only meaningful for scenes created at runtime via
        `SceneAccessor.create`; static scenes defined in YAML cannot be
        deleted this way and Home Assistant will surface an error.

        Notes
        -----
        The local entity object is **not** removed from the registry by
        this call. Callers that want to discard the proxy should also
        drop their reference.

        Raises
        ------
        CommandError
            If Home Assistant rejects the call (for example, the scene
            is YAML-defined and not deletable).
        HTTPError
            If the REST call returns a non-2xx response.
        TimeoutError
            If the call exceeds the configured request timeout.
        ConnectionClosedError
            If the WebSocket disconnects mid-call.
        """
        await self._call_service("delete")

    # -- Listener decorators ------------------------------------------

    def on_activate(self, func: ValueChangeHandler) -> ValueChangeHandler:
        """Register a listener that fires when the scene is activated.

        Parameters
        ----------
        func : callable
            Sync or async callable invoked with ``(old_state, new_state)``
            ISO-8601 activation-timestamp strings whenever the scene is
            re-activated.

        Returns
        -------
        callable
            The same *func*, returned for decorator use.
        """
        return self._register_state_value_listener(func)

last_activated property

last_activated: str | None

ISO-8601 timestamp of the last activation, or None.

entity_ids property

entity_ids: list[str]

Entity IDs controlled by this scene.

name property

name: str | None

Human-readable name of the scene.

Returns:

Type Description
str or None

The HA friendly_name attribute, or None when the entity does not advertise one. Note that this property deliberately does not return the scene's entity_id or object-id slug.

icon property

icon: str | None

Icon identifier for the scene.

Returns:

Type Description
str or None

The raw HA icon attribute, typically a Material Design Icons identifier of the form "mdi:<name>". None when the entity does not advertise an icon.

activate async

activate(*, transition: float | None = None) -> None

Activate the scene.

Parameters:

Name Type Description Default
transition float or None

Seconds over which entities supporting transitions should move to their scene state.

None
Source code in src/haclient/domains/scene.py
86
87
88
89
90
91
92
93
94
95
96
97
98
async def activate(self, *, transition: float | None = None) -> None:
    """Activate the scene.

    Parameters
    ----------
    transition : float or None, optional
        Seconds over which entities supporting transitions should
        move to their scene state.
    """
    data: dict[str, Any] | None = None
    if transition is not None:
        data = {"transition": transition}
    await self._call_service("turn_on", data)

delete async

delete() -> None

Delete this dynamically-created scene.

Invokes the scene.delete Home Assistant service. This is only meaningful for scenes created at runtime via SceneAccessor.create; static scenes defined in YAML cannot be deleted this way and Home Assistant will surface an error.

Notes

The local entity object is not removed from the registry by this call. Callers that want to discard the proxy should also drop their reference.

Raises:

Type Description
CommandError

If Home Assistant rejects the call (for example, the scene is YAML-defined and not deletable).

HTTPError

If the REST call returns a non-2xx response.

TimeoutError

If the call exceeds the configured request timeout.

ConnectionClosedError

If the WebSocket disconnects mid-call.

Source code in src/haclient/domains/scene.py
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
async def delete(self) -> None:
    """Delete this dynamically-created scene.

    Invokes the ``scene.delete`` Home Assistant service. This is
    only meaningful for scenes created at runtime via
    `SceneAccessor.create`; static scenes defined in YAML cannot be
    deleted this way and Home Assistant will surface an error.

    Notes
    -----
    The local entity object is **not** removed from the registry by
    this call. Callers that want to discard the proxy should also
    drop their reference.

    Raises
    ------
    CommandError
        If Home Assistant rejects the call (for example, the scene
        is YAML-defined and not deletable).
    HTTPError
        If the REST call returns a non-2xx response.
    TimeoutError
        If the call exceeds the configured request timeout.
    ConnectionClosedError
        If the WebSocket disconnects mid-call.
    """
    await self._call_service("delete")

on_activate

on_activate(func: ValueChangeHandler) -> ValueChangeHandler

Register a listener that fires when the scene is activated.

Parameters:

Name Type Description Default
func callable

Sync or async callable invoked with (old_state, new_state) ISO-8601 activation-timestamp strings whenever the scene is re-activated.

required

Returns:

Type Description
callable

The same func, returned for decorator use.

Source code in src/haclient/domains/scene.py
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
def on_activate(self, func: ValueChangeHandler) -> ValueChangeHandler:
    """Register a listener that fires when the scene is activated.

    Parameters
    ----------
    func : callable
        Sync or async callable invoked with ``(old_state, new_state)``
        ISO-8601 activation-timestamp strings whenever the scene is
        re-activated.

    Returns
    -------
    callable
        The same *func*, returned for decorator use.
    """
    return self._register_state_value_listener(func)

SceneAccessor

Bases: DomainAccessor[Scene]

Typed domain accessor for the scene domain.

Returned by ha.scene. Provides statically-typed collection-level operations in addition to the standard entity lookup methods inherited from DomainAccessor.

Source code in src/haclient/domains/scene.py
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
class SceneAccessor(DomainAccessor[Scene]):
    """Typed domain accessor for the ``scene`` domain.

    Returned by ``ha.scene``. Provides statically-typed collection-level
    operations in addition to the standard entity lookup methods inherited
    from `DomainAccessor`.
    """

    async def create(
        self,
        scene_id: str,
        entities: dict[str, dict[str, Any]],
        *,
        snapshot_entities: list[str] | None = None,
    ) -> Scene:
        """Create (or update) a runtime scene helper.

        Parameters
        ----------
        scene_id : str
            Object-id for the new scene (e.g. ``"romantic"`` →
            ``scene.romantic``).
        entities : dict
            Mapping of entity ids to target state/attribute dicts.
        snapshot_entities : list of str or None, optional
            Entity ids whose current state should be captured instead of
            providing an explicit state dict.

        Returns
        -------
        Scene
            The newly created (or updated) scene entity.
        """
        from haclient.core.factory import EntityFactory

        factory = self.factory
        assert isinstance(factory, EntityFactory)
        payload: dict[str, Any] = {"scene_id": scene_id, "entities": entities}
        if snapshot_entities is not None:
            payload["snapshot_entities"] = snapshot_entities
        await factory.services.call("scene", "create", payload)
        return self[scene_id]

    async def apply(
        self,
        entities: dict[str, dict[str, Any]],
        *,
        transition: float | None = None,
    ) -> None:
        """Apply a scene-like state combination without persisting it.

        Parameters
        ----------
        entities : dict
            Mapping of entity ids to desired state/attribute dicts.
        transition : float or None, optional
            Transition seconds for entities that support it.
        """
        from haclient.core.factory import EntityFactory

        factory = self.factory
        assert isinstance(factory, EntityFactory)
        payload: dict[str, Any] = {"entities": entities}
        if transition is not None:
            payload["transition"] = transition
        await factory.services.call("scene", "apply", payload)

create async

create(scene_id: str, entities: dict[str, dict[str, Any]], *, snapshot_entities: list[str] | None = None) -> Scene

Create (or update) a runtime scene helper.

Parameters:

Name Type Description Default
scene_id str

Object-id for the new scene (e.g. "romantic"scene.romantic).

required
entities dict

Mapping of entity ids to target state/attribute dicts.

required
snapshot_entities list of str or None

Entity ids whose current state should be captured instead of providing an explicit state dict.

None

Returns:

Type Description
Scene

The newly created (or updated) scene entity.

Source code in src/haclient/domains/scene.py
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
async def create(
    self,
    scene_id: str,
    entities: dict[str, dict[str, Any]],
    *,
    snapshot_entities: list[str] | None = None,
) -> Scene:
    """Create (or update) a runtime scene helper.

    Parameters
    ----------
    scene_id : str
        Object-id for the new scene (e.g. ``"romantic"`` →
        ``scene.romantic``).
    entities : dict
        Mapping of entity ids to target state/attribute dicts.
    snapshot_entities : list of str or None, optional
        Entity ids whose current state should be captured instead of
        providing an explicit state dict.

    Returns
    -------
    Scene
        The newly created (or updated) scene entity.
    """
    from haclient.core.factory import EntityFactory

    factory = self.factory
    assert isinstance(factory, EntityFactory)
    payload: dict[str, Any] = {"scene_id": scene_id, "entities": entities}
    if snapshot_entities is not None:
        payload["snapshot_entities"] = snapshot_entities
    await factory.services.call("scene", "create", payload)
    return self[scene_id]

apply async

apply(entities: dict[str, dict[str, Any]], *, transition: float | None = None) -> None

Apply a scene-like state combination without persisting it.

Parameters:

Name Type Description Default
entities dict

Mapping of entity ids to desired state/attribute dicts.

required
transition float or None

Transition seconds for entities that support it.

None
Source code in src/haclient/domains/scene.py
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
async def apply(
    self,
    entities: dict[str, dict[str, Any]],
    *,
    transition: float | None = None,
) -> None:
    """Apply a scene-like state combination without persisting it.

    Parameters
    ----------
    entities : dict
        Mapping of entity ids to desired state/attribute dicts.
    transition : float or None, optional
        Transition seconds for entities that support it.
    """
    from haclient.core.factory import EntityFactory

    factory = self.factory
    assert isinstance(factory, EntityFactory)
    payload: dict[str, Any] = {"entities": entities}
    if transition is not None:
        payload["transition"] = transition
    await factory.services.call("scene", "apply", payload)