pywmswebcontrolpro 0.1.1__tar.gz → 0.1.2__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.
Files changed (32) hide show
  1. {pywmswebcontrolpro-0.1.1 → pywmswebcontrolpro-0.1.2}/PKG-INFO +1 -1
  2. {pywmswebcontrolpro-0.1.1 → pywmswebcontrolpro-0.1.2}/pywmswebcontrolpro/webcontrol.py +24 -3
  3. {pywmswebcontrolpro-0.1.1 → pywmswebcontrolpro-0.1.2}/tests/conftest.py +2 -1
  4. pywmswebcontrolpro-0.1.2/tests/test_configuration.py +59 -0
  5. {pywmswebcontrolpro-0.1.1 → pywmswebcontrolpro-0.1.2}/.github/workflows/release.yaml +0 -0
  6. {pywmswebcontrolpro-0.1.1 → pywmswebcontrolpro-0.1.2}/.github/workflows/validate.yaml +0 -0
  7. {pywmswebcontrolpro-0.1.1 → pywmswebcontrolpro-0.1.2}/.gitignore +0 -0
  8. {pywmswebcontrolpro-0.1.1 → pywmswebcontrolpro-0.1.2}/.python-version +0 -0
  9. {pywmswebcontrolpro-0.1.1 → pywmswebcontrolpro-0.1.2}/LICENSE +0 -0
  10. {pywmswebcontrolpro-0.1.1 → pywmswebcontrolpro-0.1.2}/README.md +0 -0
  11. {pywmswebcontrolpro-0.1.1 → pywmswebcontrolpro-0.1.2}/mypy.ini +0 -0
  12. {pywmswebcontrolpro-0.1.1 → pywmswebcontrolpro-0.1.2}/pyproject.toml +0 -0
  13. {pywmswebcontrolpro-0.1.1 → pywmswebcontrolpro-0.1.2}/pytest.ini +0 -0
  14. {pywmswebcontrolpro-0.1.1 → pywmswebcontrolpro-0.1.2}/pywmswebcontrolpro/__init__.py +0 -0
  15. {pywmswebcontrolpro-0.1.1 → pywmswebcontrolpro-0.1.2}/pywmswebcontrolpro/action.py +0 -0
  16. {pywmswebcontrolpro-0.1.1 → pywmswebcontrolpro-0.1.2}/pywmswebcontrolpro/const.py +0 -0
  17. {pywmswebcontrolpro-0.1.1 → pywmswebcontrolpro-0.1.2}/pywmswebcontrolpro/destination.py +0 -0
  18. {pywmswebcontrolpro-0.1.1 → pywmswebcontrolpro-0.1.2}/pywmswebcontrolpro/py.typed +0 -0
  19. {pywmswebcontrolpro-0.1.1 → pywmswebcontrolpro-0.1.2}/pywmswebcontrolpro/refresh.py +0 -0
  20. {pywmswebcontrolpro-0.1.1 → pywmswebcontrolpro-0.1.2}/pywmswebcontrolpro/room.py +0 -0
  21. {pywmswebcontrolpro-0.1.1 → pywmswebcontrolpro-0.1.2}/pywmswebcontrolpro/scene.py +0 -0
  22. {pywmswebcontrolpro-0.1.1 → pywmswebcontrolpro-0.1.2}/pywmswebcontrolpro/store.py +0 -0
  23. {pywmswebcontrolpro-0.1.1 → pywmswebcontrolpro-0.1.2}/pywmswebcontrolpro/travel.py +0 -0
  24. {pywmswebcontrolpro-0.1.1 → pywmswebcontrolpro-0.1.2}/requirements_lint.txt +0 -0
  25. {pywmswebcontrolpro-0.1.1 → pywmswebcontrolpro-0.1.2}/requirements_test.txt +0 -0
  26. {pywmswebcontrolpro-0.1.1 → pywmswebcontrolpro-0.1.2}/ruff.toml +0 -0
  27. {pywmswebcontrolpro-0.1.1 → pywmswebcontrolpro-0.1.2}/simulator/simulator.py +0 -0
  28. {pywmswebcontrolpro-0.1.1 → pywmswebcontrolpro-0.1.2}/tests/__init__.py +0 -0
  29. {pywmswebcontrolpro-0.1.1 → pywmswebcontrolpro-0.1.2}/tests/test_import.py +0 -0
  30. {pywmswebcontrolpro-0.1.1 → pywmswebcontrolpro-0.1.2}/tests/test_refresh.py +0 -0
  31. {pywmswebcontrolpro-0.1.1 → pywmswebcontrolpro-0.1.2}/tests/test_settings.py +0 -0
  32. {pywmswebcontrolpro-0.1.1 → pywmswebcontrolpro-0.1.2}/tests/test_travel.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: pywmswebcontrolpro
3
- Version: 0.1.1
3
+ Version: 0.1.2
4
4
  Summary: Python library for the Warema WMS WebControl pro API
5
5
  Author-email: Marc Hoersken <info@marc-hoersken.de>
6
6
  License-Expression: Apache-2.0
@@ -4,6 +4,7 @@ import asyncio
4
4
  import pprint
5
5
  import time
6
6
  from collections.abc import Mapping
7
+ from dataclasses import dataclass
7
8
  from datetime import timedelta
8
9
  from pathlib import Path
9
10
  from types import MappingProxyType
@@ -33,6 +34,14 @@ DEFAULT_RETRY_DELAY = 1.0
33
34
  DEFAULT_REQUEST_SPACING = 0.5
34
35
 
35
36
 
37
+ @dataclass(frozen=True)
38
+ class ConfigChanges:
39
+ """Destinations that appeared or disappeared with a configuration refresh."""
40
+
41
+ added: frozenset[int] = frozenset()
42
+ removed: frozenset[int] = frozenset()
43
+
44
+
36
45
  class WebControlPro:
37
46
  """Client of one WMS WebControl pro gateway."""
38
47
 
@@ -143,15 +152,27 @@ class WebControlPro:
143
152
  ping = await self._ping()
144
153
  return ping["status"] == 0
145
154
 
146
- async def refresh(self) -> None:
147
- """Read the configuration and create destinations, rooms and scenes."""
155
+ async def refresh(self) -> ConfigChanges:
156
+ """Read the configuration and create destinations, rooms and scenes.
157
+
158
+ A destination that is already known stays the same object, so its
159
+ actions keep their movement model and stored state. Only new
160
+ destinations are created, and the result names the destinations that
161
+ appeared and disappeared. Rooms and scenes are created again.
162
+ """
148
163
  config = await self._getConfiguration()
149
164
  self._config = config
165
+ known = self._dests
150
166
  self._dests = {
151
- dest["id"]: Destination(self, **dest) for dest in config["destinations"]
167
+ dest["id"]: known.get(dest["id"]) or Destination(self, **dest)
168
+ for dest in config["destinations"]
152
169
  }
153
170
  self._rooms = {room["id"]: Room(self, **room) for room in config["rooms"]}
154
171
  self._scenes = {scene["id"]: Scene(self, **scene) for scene in config["scenes"]}
172
+ return ConfigChanges(
173
+ added=frozenset(self._dests) - frozenset(known),
174
+ removed=frozenset(known) - frozenset(self._dests),
175
+ )
155
176
 
156
177
  def dest(self, name: str) -> Destination:
157
178
  """Return the destination with the given name or raise KeyError."""
@@ -106,12 +106,13 @@ class FakeGateway:
106
106
  def __init__(self) -> None:
107
107
  self.status_answers: list[dict[str, Any] | Exception] = []
108
108
  self.requests: list[dict[str, Any]] = []
109
+ self.config = CONFIG
109
110
 
110
111
  def post(self, url: str, json: dict[str, Any], timeout: int) -> FakeRequest:
111
112
  """Answer one request of the library."""
112
113
  self.requests.append(json)
113
114
  if json["command"] == "getConfiguration":
114
- return FakeRequest(CONFIG)
115
+ return FakeRequest(self.config)
115
116
  return FakeRequest(self.status_answers.pop(0))
116
117
 
117
118
  @property
@@ -0,0 +1,59 @@
1
+ """Tests for reading the configuration of the gateway again."""
2
+
3
+ from collections.abc import Callable
4
+ from copy import deepcopy
5
+ from typing import Any
6
+
7
+ from pywmswebcontrolpro.webcontrol import ConfigChanges, WebControlPro
8
+
9
+ from .conftest import CONFIG, DEST_ID, FakeGateway
10
+
11
+ NEW_DEST_ID = 8
12
+
13
+
14
+ def _config_with(*dest_ids: int) -> dict[str, Any]:
15
+ """Return a configuration with copies of the test destination."""
16
+ config = deepcopy(CONFIG)
17
+ template = config["destinations"][0]
18
+ config["destinations"] = [{**template, "id": dest_id} for dest_id in dest_ids]
19
+ return config
20
+
21
+
22
+ async def test_first_refresh_reports_all_destinations_as_added(
23
+ make_control: Callable[..., WebControlPro],
24
+ ) -> None:
25
+ """The first read of the configuration finds the destinations."""
26
+ changes = await make_control().refresh()
27
+
28
+ assert changes == ConfigChanges(added=frozenset({DEST_ID}))
29
+
30
+
31
+ async def test_refresh_reports_added_and_removed_destinations(
32
+ make_control: Callable[..., WebControlPro], gateway: FakeGateway
33
+ ) -> None:
34
+ """A destination that appears or disappears is named in the result."""
35
+ control = make_control()
36
+ await control.refresh()
37
+ gateway.config = _config_with(NEW_DEST_ID)
38
+
39
+ changes = await control.refresh()
40
+
41
+ assert changes == ConfigChanges(
42
+ added=frozenset({NEW_DEST_ID}), removed=frozenset({DEST_ID})
43
+ )
44
+ assert set(control.dests) == {NEW_DEST_ID}
45
+
46
+
47
+ async def test_refresh_keeps_the_known_destinations(
48
+ make_control: Callable[..., WebControlPro], gateway: FakeGateway
49
+ ) -> None:
50
+ """A known destination stays the same object with its state."""
51
+ control = make_control()
52
+ await control.refresh()
53
+ known = control.dests[DEST_ID]
54
+ gateway.config = _config_with(DEST_ID, NEW_DEST_ID)
55
+
56
+ changes = await control.refresh()
57
+
58
+ assert changes == ConfigChanges(added=frozenset({NEW_DEST_ID}))
59
+ assert control.dests[DEST_ID] is known