|
6 | 6 | Domain-level operations |
7 | 7 | ----------------------- |
8 | 8 | Beyond per-entity actions, the scene domain exposes two collection-level |
9 | | -operations on the `DomainAccessor`: |
| 9 | +operations on the `SceneAccessor` (returned by ``ha.scene``): |
10 | 10 |
|
11 | | -* ``create(scene_id, entities, *, snapshot_entities=None) -> Scene`` — |
12 | | - create (or update) a runtime scene helper. |
13 | | -* ``apply(entities, *, transition=None) -> None`` — apply a state |
14 | | - combination without persisting it. |
| 11 | +* ``await ha.scene.create(scene_id, entities, *, snapshot_entities=None)`` |
| 12 | + — create (or update) a runtime scene helper, returning a `Scene`. |
| 13 | +* ``await ha.scene.apply(entities, *, transition=None)`` |
| 14 | + — apply a state combination without persisting it. |
15 | 15 |
|
16 | | -These are invoked as ``await ha.scene.create(...)`` and |
17 | | -``await ha.scene.apply(...)``. Per-entity access still works through the |
18 | | -usual ``ha.scene("name")`` / ``ha.scene["name"]`` syntax. |
| 16 | +Per-entity access still works through the usual |
| 17 | +``ha.scene("name")`` / ``ha.scene["name"]`` syntax. |
19 | 18 | """ |
20 | 19 |
|
21 | 20 | from __future__ import annotations |
22 | 21 |
|
23 | | -from typing import TYPE_CHECKING, Any |
| 22 | +from typing import Any |
24 | 23 |
|
25 | 24 | from haclient.core.plugins import DomainAccessor, DomainSpec, register_domain |
26 | 25 | from haclient.entity.base import Entity, ValueChangeHandler |
27 | 26 |
|
28 | | -if TYPE_CHECKING: |
29 | | - from haclient.core.factory import EntityFactory |
30 | | - |
31 | 27 |
|
32 | 28 | class Scene(Entity): |
33 | 29 | """A Home Assistant scene entity. |
@@ -108,74 +104,82 @@ def on_activate(self, func: ValueChangeHandler) -> ValueChangeHandler: |
108 | 104 | return self._register_state_value_listener(func) |
109 | 105 |
|
110 | 106 |
|
111 | | -# -- Domain-level operations -------------------------------------------- |
112 | | - |
113 | | - |
114 | | -async def _create( |
115 | | - accessor: DomainAccessor[Scene], |
116 | | - scene_id: str, |
117 | | - entities: dict[str, dict[str, Any]], |
118 | | - *, |
119 | | - snapshot_entities: list[str] | None = None, |
120 | | -) -> Scene: |
121 | | - """Create a runtime scene and return the corresponding `Scene`. |
122 | | -
|
123 | | - Parameters |
124 | | - ---------- |
125 | | - accessor : DomainAccessor |
126 | | - The scene accessor (provided automatically by the binding). |
127 | | - scene_id : str |
128 | | - Object-id for the new scene (e.g. ``"romantic"`` → |
129 | | - ``scene.romantic``). |
130 | | - entities : dict |
131 | | - Mapping of entity ids to state/attribute dicts. |
132 | | - snapshot_entities : list of str or None, optional |
133 | | - Entity ids whose current state should be captured. |
134 | | -
|
135 | | - Returns |
136 | | - ------- |
137 | | - Scene |
138 | | - The newly created scene. |
139 | | - """ |
140 | | - factory: EntityFactory = accessor._factory # type: ignore[assignment] |
141 | | - services = factory.services |
142 | | - payload: dict[str, Any] = {"scene_id": scene_id, "entities": entities} |
143 | | - if snapshot_entities is not None: |
144 | | - payload["snapshot_entities"] = snapshot_entities |
145 | | - await services.call("scene", "create", payload) |
146 | | - return accessor[scene_id] |
147 | | - |
148 | | - |
149 | | -async def _apply( |
150 | | - accessor: DomainAccessor[Scene], |
151 | | - entities: dict[str, dict[str, Any]], |
152 | | - *, |
153 | | - transition: float | None = None, |
154 | | -) -> None: |
155 | | - """Apply a scene-like state combination without persisting it. |
156 | | -
|
157 | | - Parameters |
158 | | - ---------- |
159 | | - accessor : DomainAccessor |
160 | | - The scene accessor. |
161 | | - entities : dict |
162 | | - Mapping of entity ids to desired state/attribute dicts. |
163 | | - transition : float or None, optional |
164 | | - Transition seconds for entities that support it. |
| 107 | +# -- Typed domain accessor ---------------------------------------------- |
| 108 | + |
| 109 | + |
| 110 | +class SceneAccessor(DomainAccessor[Scene]): |
| 111 | + """Typed domain accessor for the ``scene`` domain. |
| 112 | +
|
| 113 | + Returned by ``ha.scene``. Provides statically-typed collection-level |
| 114 | + operations in addition to the standard entity lookup methods inherited |
| 115 | + from `DomainAccessor`. |
165 | 116 | """ |
166 | | - factory: EntityFactory = accessor._factory # type: ignore[assignment] |
167 | | - services = factory.services |
168 | | - payload: dict[str, Any] = {"entities": entities} |
169 | | - if transition is not None: |
170 | | - payload["transition"] = transition |
171 | | - await services.call("scene", "apply", payload) |
| 117 | + |
| 118 | + async def create( |
| 119 | + self, |
| 120 | + scene_id: str, |
| 121 | + entities: dict[str, dict[str, Any]], |
| 122 | + *, |
| 123 | + snapshot_entities: list[str] | None = None, |
| 124 | + ) -> Scene: |
| 125 | + """Create (or update) a runtime scene helper. |
| 126 | +
|
| 127 | + Parameters |
| 128 | + ---------- |
| 129 | + scene_id : str |
| 130 | + Object-id for the new scene (e.g. ``"romantic"`` → |
| 131 | + ``scene.romantic``). |
| 132 | + entities : dict |
| 133 | + Mapping of entity ids to target state/attribute dicts. |
| 134 | + snapshot_entities : list of str or None, optional |
| 135 | + Entity ids whose current state should be captured instead of |
| 136 | + providing an explicit state dict. |
| 137 | +
|
| 138 | + Returns |
| 139 | + ------- |
| 140 | + Scene |
| 141 | + The newly created (or updated) scene entity. |
| 142 | + """ |
| 143 | + from haclient.core.factory import EntityFactory |
| 144 | + |
| 145 | + factory = self.factory |
| 146 | + assert isinstance(factory, EntityFactory) |
| 147 | + payload: dict[str, Any] = {"scene_id": scene_id, "entities": entities} |
| 148 | + if snapshot_entities is not None: |
| 149 | + payload["snapshot_entities"] = snapshot_entities |
| 150 | + await factory.services.call("scene", "create", payload) |
| 151 | + return self[scene_id] |
| 152 | + |
| 153 | + async def apply( |
| 154 | + self, |
| 155 | + entities: dict[str, dict[str, Any]], |
| 156 | + *, |
| 157 | + transition: float | None = None, |
| 158 | + ) -> None: |
| 159 | + """Apply a scene-like state combination without persisting it. |
| 160 | +
|
| 161 | + Parameters |
| 162 | + ---------- |
| 163 | + entities : dict |
| 164 | + Mapping of entity ids to desired state/attribute dicts. |
| 165 | + transition : float or None, optional |
| 166 | + Transition seconds for entities that support it. |
| 167 | + """ |
| 168 | + from haclient.core.factory import EntityFactory |
| 169 | + |
| 170 | + factory = self.factory |
| 171 | + assert isinstance(factory, EntityFactory) |
| 172 | + payload: dict[str, Any] = {"entities": entities} |
| 173 | + if transition is not None: |
| 174 | + payload["transition"] = transition |
| 175 | + await factory.services.call("scene", "apply", payload) |
172 | 176 |
|
173 | 177 |
|
174 | 178 | SPEC: DomainSpec[Scene] = register_domain( |
175 | 179 | DomainSpec( |
176 | 180 | name="scene", |
177 | 181 | entity_cls=Scene, |
178 | | - operations={"create": _create, "apply": _apply}, |
| 182 | + accessor_cls=SceneAccessor, |
179 | 183 | ) |
180 | 184 | ) |
181 | 185 | """The `DomainSpec` registered with the shared `DomainRegistry`.""" |
0 commit comments