python-rako-2025 0.3.0__tar.gz → 0.3.8__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {python_rako_2025-0.3.0 → python_rako_2025-0.3.8}/PKG-INFO +1 -1
- python_rako_2025-0.3.8/python_rako/__version__.py +1 -0
- {python_rako_2025-0.3.0 → python_rako_2025-0.3.8}/python_rako/bridge.py +52 -37
- {python_rako_2025-0.3.0 → python_rako_2025-0.3.8}/python_rako_2025.egg-info/PKG-INFO +1 -1
- python_rako_2025-0.3.0/python_rako/__version__.py +0 -1
- {python_rako_2025-0.3.0 → python_rako_2025-0.3.8}/LICENSE +0 -0
- {python_rako_2025-0.3.0 → python_rako_2025-0.3.8}/README.md +0 -0
- {python_rako_2025-0.3.0 → python_rako_2025-0.3.8}/pyproject.toml +0 -0
- {python_rako_2025-0.3.0 → python_rako_2025-0.3.8}/python_rako/__init__.py +0 -0
- {python_rako_2025-0.3.0 → python_rako_2025-0.3.8}/python_rako/const.py +0 -0
- {python_rako_2025-0.3.0 → python_rako_2025-0.3.8}/python_rako/exceptions.py +0 -0
- {python_rako_2025-0.3.0 → python_rako_2025-0.3.8}/python_rako/helpers.py +0 -0
- {python_rako_2025-0.3.0 → python_rako_2025-0.3.8}/python_rako/model.py +0 -0
- {python_rako_2025-0.3.0 → python_rako_2025-0.3.8}/python_rako/py.typed +0 -0
- {python_rako_2025-0.3.0 → python_rako_2025-0.3.8}/python_rako_2025.egg-info/SOURCES.txt +0 -0
- {python_rako_2025-0.3.0 → python_rako_2025-0.3.8}/python_rako_2025.egg-info/dependency_links.txt +0 -0
- {python_rako_2025-0.3.0 → python_rako_2025-0.3.8}/python_rako_2025.egg-info/requires.txt +0 -0
- {python_rako_2025-0.3.0 → python_rako_2025-0.3.8}/python_rako_2025.egg-info/top_level.txt +0 -0
- {python_rako_2025-0.3.0 → python_rako_2025-0.3.8}/setup.cfg +0 -0
- {python_rako_2025-0.3.0 → python_rako_2025-0.3.8}/setup.py +0 -0
- {python_rako_2025-0.3.0 → python_rako_2025-0.3.8}/tests/test_bridge.py +0 -0
- {python_rako_2025-0.3.0 → python_rako_2025-0.3.8}/tests/test_helpers.py +0 -0
- {python_rako_2025-0.3.0 → python_rako_2025-0.3.8}/tests/test_model.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: python-rako-2025
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.8
|
|
4
4
|
Summary: Asynchronous Python client for Rako Controls Lighting
|
|
5
5
|
Author-email: Simon Leigh <simonleigh@users.noreply.github.com>
|
|
6
6
|
Project-URL: Homepage, https://github.com/simonleigh/python-rako
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
0.3.8
|
|
@@ -32,11 +32,9 @@ from python_rako.model import (
|
|
|
32
32
|
CommandUDP,
|
|
33
33
|
EOFResponse,
|
|
34
34
|
LevelCache,
|
|
35
|
-
Light,
|
|
36
35
|
RoomLight,
|
|
37
36
|
RoomVentilation,
|
|
38
37
|
SceneCache,
|
|
39
|
-
Ventilation,
|
|
40
38
|
)
|
|
41
39
|
|
|
42
40
|
_LOGGER = logging.getLogger(__name__)
|
|
@@ -150,64 +148,76 @@ class Bridge:
|
|
|
150
148
|
)
|
|
151
149
|
self.level_cache: LevelCache = LevelCache()
|
|
152
150
|
self.scene_cache: SceneCache = SceneCache()
|
|
151
|
+
self._cached_xml: str | None = None
|
|
153
152
|
|
|
154
153
|
@property
|
|
155
154
|
def _discovery_url(self) -> str:
|
|
156
155
|
return f"http://{self.host}/rako.xml"
|
|
157
156
|
|
|
158
|
-
async def get_rako_xml(
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
157
|
+
async def get_rako_xml(
|
|
158
|
+
self, session: aiohttp.ClientSession, force_refresh: bool = False
|
|
159
|
+
) -> str:
|
|
160
|
+
if self._cached_xml is None or force_refresh:
|
|
161
|
+
async with session.get(self._discovery_url) as response:
|
|
162
|
+
self._cached_xml = await response.text()
|
|
163
|
+
assert self._cached_xml is not None
|
|
164
|
+
return self._cached_xml
|
|
162
165
|
|
|
163
166
|
async def discover_devices(
|
|
164
|
-
self, session: aiohttp.ClientSession
|
|
165
|
-
) -> tuple[
|
|
166
|
-
|
|
167
|
-
|
|
167
|
+
self, session: aiohttp.ClientSession, force_refresh: bool = False
|
|
168
|
+
) -> tuple[
|
|
169
|
+
list[RoomLight | ChannelLight], list[RoomVentilation | ChannelVentilation]
|
|
170
|
+
]:
|
|
171
|
+
"""Discover all devices by fetching XML once and parsing all device types.
|
|
172
|
+
|
|
168
173
|
Returns a tuple of (lights, ventilation) to avoid race conditions.
|
|
169
174
|
"""
|
|
170
|
-
rako_xml = await self.get_rako_xml(session)
|
|
171
|
-
|
|
172
|
-
lights = []
|
|
173
|
-
ventilation = []
|
|
174
|
-
|
|
175
|
+
rako_xml = await self.get_rako_xml(session, force_refresh)
|
|
176
|
+
|
|
177
|
+
lights: list[RoomLight | ChannelLight] = []
|
|
178
|
+
ventilation: list[RoomVentilation | ChannelVentilation] = []
|
|
179
|
+
|
|
175
180
|
for device in self.get_devices_from_discovery_xml(rako_xml):
|
|
176
181
|
if isinstance(device, (RoomLight, ChannelLight)):
|
|
177
182
|
lights.append(device)
|
|
178
183
|
elif isinstance(device, (RoomVentilation, ChannelVentilation)):
|
|
179
184
|
ventilation.append(device)
|
|
180
|
-
|
|
185
|
+
|
|
181
186
|
return lights, ventilation
|
|
182
187
|
|
|
183
188
|
async def discover_lights(
|
|
184
|
-
self, session: aiohttp.ClientSession
|
|
185
|
-
) -> AsyncGenerator[
|
|
189
|
+
self, session: aiohttp.ClientSession, force_refresh: bool = False
|
|
190
|
+
) -> AsyncGenerator[RoomLight | ChannelLight]:
|
|
186
191
|
"""Discover lights by fetching XML once and filtering for lights."""
|
|
187
|
-
|
|
188
|
-
for light in
|
|
192
|
+
lights, _ = await self.discover_devices(session, force_refresh)
|
|
193
|
+
for light in lights:
|
|
189
194
|
yield light
|
|
190
195
|
|
|
191
196
|
async def discover_ventilation(
|
|
192
|
-
self, session: aiohttp.ClientSession
|
|
193
|
-
) -> AsyncGenerator[
|
|
197
|
+
self, session: aiohttp.ClientSession, force_refresh: bool = False
|
|
198
|
+
) -> AsyncGenerator[RoomVentilation | ChannelVentilation]:
|
|
194
199
|
"""Discover ventilation by fetching XML once and filtering for ventilation."""
|
|
195
|
-
|
|
196
|
-
for
|
|
197
|
-
|
|
198
|
-
yield device
|
|
200
|
+
_, ventilation = await self.discover_devices(session, force_refresh)
|
|
201
|
+
for vent in ventilation:
|
|
202
|
+
yield vent
|
|
199
203
|
|
|
200
204
|
async def discover_all_devices(
|
|
201
|
-
self, session: aiohttp.ClientSession
|
|
202
|
-
) -> AsyncGenerator[
|
|
205
|
+
self, session: aiohttp.ClientSession, force_refresh: bool = False
|
|
206
|
+
) -> AsyncGenerator[
|
|
207
|
+
RoomLight | ChannelLight | RoomVentilation | ChannelVentilation
|
|
208
|
+
]:
|
|
203
209
|
"""Discover all devices by fetching XML once."""
|
|
204
|
-
|
|
205
|
-
for
|
|
206
|
-
yield
|
|
210
|
+
lights, ventilation = await self.discover_devices(session, force_refresh)
|
|
211
|
+
for light in lights:
|
|
212
|
+
yield light
|
|
213
|
+
for vent in ventilation:
|
|
214
|
+
yield vent
|
|
207
215
|
|
|
208
|
-
async def get_info(
|
|
216
|
+
async def get_info(
|
|
217
|
+
self, session: aiohttp.ClientSession, force_refresh: bool = False
|
|
218
|
+
) -> BridgeInfo:
|
|
209
219
|
try:
|
|
210
|
-
rako_xml = await self.get_rako_xml(session)
|
|
220
|
+
rako_xml = await self.get_rako_xml(session, force_refresh)
|
|
211
221
|
info = self.get_bridge_info_from_discovery_xml(rako_xml)
|
|
212
222
|
except (KeyError, ValueError) as ex:
|
|
213
223
|
raise RakoBridgeError(f"unsupported bridge: {ex}")
|
|
@@ -234,20 +244,24 @@ class Bridge:
|
|
|
234
244
|
)
|
|
235
245
|
|
|
236
246
|
@staticmethod
|
|
237
|
-
def get_lights_from_discovery_xml(
|
|
247
|
+
def get_lights_from_discovery_xml(
|
|
248
|
+
xml: str,
|
|
249
|
+
) -> Generator[RoomLight | ChannelLight]:
|
|
238
250
|
for device in Bridge.get_devices_from_discovery_xml(xml, "Lights"):
|
|
239
251
|
if isinstance(device, (RoomLight, ChannelLight)):
|
|
240
252
|
yield device
|
|
241
253
|
|
|
242
254
|
@staticmethod
|
|
243
|
-
def get_all_devices_from_discovery_xml(
|
|
255
|
+
def get_all_devices_from_discovery_xml(
|
|
256
|
+
xml: str,
|
|
257
|
+
) -> Generator[RoomLight | ChannelLight | RoomVentilation | ChannelVentilation]:
|
|
244
258
|
"""Get all devices (lights and ventilation) from discovery XML."""
|
|
245
259
|
return Bridge.get_devices_from_discovery_xml(xml)
|
|
246
260
|
|
|
247
261
|
@staticmethod
|
|
248
262
|
def get_devices_from_discovery_xml(
|
|
249
263
|
xml: str, device_types: str | list[str] | None = None
|
|
250
|
-
) -> Generator[
|
|
264
|
+
) -> Generator[RoomLight | ChannelLight | RoomVentilation | ChannelVentilation]:
|
|
251
265
|
# Handle different input types for backward compatibility
|
|
252
266
|
if device_types is None or device_types == "All":
|
|
253
267
|
target_types = {"Lights", "Ventilation"}
|
|
@@ -307,7 +321,8 @@ class Bridge:
|
|
|
307
321
|
if not resp:
|
|
308
322
|
return None
|
|
309
323
|
|
|
310
|
-
data,
|
|
324
|
+
data, addr = resp
|
|
325
|
+
remote_ip, _ = addr
|
|
311
326
|
if remote_ip != self.host:
|
|
312
327
|
return None
|
|
313
328
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: python-rako-2025
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.8
|
|
4
4
|
Summary: Asynchronous Python client for Rako Controls Lighting
|
|
5
5
|
Author-email: Simon Leigh <simonleigh@users.noreply.github.com>
|
|
6
6
|
Project-URL: Homepage, https://github.com/simonleigh/python-rako
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
0.3.0
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_rako_2025-0.3.0 → python_rako_2025-0.3.8}/python_rako_2025.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|