python-omnilogic-local 0.20.6__tar.gz → 0.20.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.
Files changed (61) hide show
  1. {python_omnilogic_local-0.20.6 → python_omnilogic_local-0.20.8}/PKG-INFO +4 -4
  2. {python_omnilogic_local-0.20.6 → python_omnilogic_local-0.20.8}/README.md +3 -3
  3. {python_omnilogic_local-0.20.6 → python_omnilogic_local-0.20.8}/pyomnilogic_local/api/protocol.py +6 -1
  4. {python_omnilogic_local-0.20.6 → python_omnilogic_local-0.20.8}/pyomnilogic_local/colorlogiclight.py +4 -4
  5. {python_omnilogic_local-0.20.6 → python_omnilogic_local-0.20.8}/pyomnilogic_local/models/mspconfig.py +5 -5
  6. {python_omnilogic_local-0.20.6 → python_omnilogic_local-0.20.8}/pyomnilogic_local/models/telemetry.py +3 -2
  7. {python_omnilogic_local-0.20.6 → python_omnilogic_local-0.20.8}/pyomnilogic_local/omnilogic.py +11 -0
  8. {python_omnilogic_local-0.20.6 → python_omnilogic_local-0.20.8}/pyproject.toml +2 -2
  9. {python_omnilogic_local-0.20.6 → python_omnilogic_local-0.20.8}/LICENSE +0 -0
  10. {python_omnilogic_local-0.20.6 → python_omnilogic_local-0.20.8}/pyomnilogic_local/__init__.py +0 -0
  11. {python_omnilogic_local-0.20.6 → python_omnilogic_local-0.20.8}/pyomnilogic_local/_base.py +0 -0
  12. {python_omnilogic_local-0.20.6 → python_omnilogic_local-0.20.8}/pyomnilogic_local/api/__init__.py +0 -0
  13. {python_omnilogic_local-0.20.6 → python_omnilogic_local-0.20.8}/pyomnilogic_local/api/api.py +0 -0
  14. {python_omnilogic_local-0.20.6 → python_omnilogic_local-0.20.8}/pyomnilogic_local/api/constants.py +0 -0
  15. {python_omnilogic_local-0.20.6 → python_omnilogic_local-0.20.8}/pyomnilogic_local/api/exceptions.py +0 -0
  16. {python_omnilogic_local-0.20.6 → python_omnilogic_local-0.20.8}/pyomnilogic_local/backyard.py +0 -0
  17. {python_omnilogic_local-0.20.6 → python_omnilogic_local-0.20.8}/pyomnilogic_local/bow.py +0 -0
  18. {python_omnilogic_local-0.20.6 → python_omnilogic_local-0.20.8}/pyomnilogic_local/chlorinator.py +0 -0
  19. {python_omnilogic_local-0.20.6 → python_omnilogic_local-0.20.8}/pyomnilogic_local/chlorinator_equip.py +0 -0
  20. {python_omnilogic_local-0.20.6 → python_omnilogic_local-0.20.8}/pyomnilogic_local/cli/__init__.py +0 -0
  21. {python_omnilogic_local-0.20.6 → python_omnilogic_local-0.20.8}/pyomnilogic_local/cli/cli.py +0 -0
  22. {python_omnilogic_local-0.20.6 → python_omnilogic_local-0.20.8}/pyomnilogic_local/cli/debug/__init__.py +0 -0
  23. {python_omnilogic_local-0.20.6 → python_omnilogic_local-0.20.8}/pyomnilogic_local/cli/debug/commands.py +0 -0
  24. {python_omnilogic_local-0.20.6 → python_omnilogic_local-0.20.8}/pyomnilogic_local/cli/get/__init__.py +0 -0
  25. {python_omnilogic_local-0.20.6 → python_omnilogic_local-0.20.8}/pyomnilogic_local/cli/get/backyard.py +0 -0
  26. {python_omnilogic_local-0.20.6 → python_omnilogic_local-0.20.8}/pyomnilogic_local/cli/get/bows.py +0 -0
  27. {python_omnilogic_local-0.20.6 → python_omnilogic_local-0.20.8}/pyomnilogic_local/cli/get/chlorinators.py +0 -0
  28. {python_omnilogic_local-0.20.6 → python_omnilogic_local-0.20.8}/pyomnilogic_local/cli/get/commands.py +0 -0
  29. {python_omnilogic_local-0.20.6 → python_omnilogic_local-0.20.8}/pyomnilogic_local/cli/get/csads.py +0 -0
  30. {python_omnilogic_local-0.20.6 → python_omnilogic_local-0.20.8}/pyomnilogic_local/cli/get/filters.py +0 -0
  31. {python_omnilogic_local-0.20.6 → python_omnilogic_local-0.20.8}/pyomnilogic_local/cli/get/groups.py +0 -0
  32. {python_omnilogic_local-0.20.6 → python_omnilogic_local-0.20.8}/pyomnilogic_local/cli/get/heaters.py +0 -0
  33. {python_omnilogic_local-0.20.6 → python_omnilogic_local-0.20.8}/pyomnilogic_local/cli/get/lights.py +0 -0
  34. {python_omnilogic_local-0.20.6 → python_omnilogic_local-0.20.8}/pyomnilogic_local/cli/get/pumps.py +0 -0
  35. {python_omnilogic_local-0.20.6 → python_omnilogic_local-0.20.8}/pyomnilogic_local/cli/get/relays.py +0 -0
  36. {python_omnilogic_local-0.20.6 → python_omnilogic_local-0.20.8}/pyomnilogic_local/cli/get/schedules.py +0 -0
  37. {python_omnilogic_local-0.20.6 → python_omnilogic_local-0.20.8}/pyomnilogic_local/cli/get/sensors.py +0 -0
  38. {python_omnilogic_local-0.20.6 → python_omnilogic_local-0.20.8}/pyomnilogic_local/cli/get/valves.py +0 -0
  39. {python_omnilogic_local-0.20.6 → python_omnilogic_local-0.20.8}/pyomnilogic_local/cli/pcap_utils.py +0 -0
  40. {python_omnilogic_local-0.20.6 → python_omnilogic_local-0.20.8}/pyomnilogic_local/cli/utils.py +0 -0
  41. {python_omnilogic_local-0.20.6 → python_omnilogic_local-0.20.8}/pyomnilogic_local/collections.py +0 -0
  42. {python_omnilogic_local-0.20.6 → python_omnilogic_local-0.20.8}/pyomnilogic_local/csad.py +0 -0
  43. {python_omnilogic_local-0.20.6 → python_omnilogic_local-0.20.8}/pyomnilogic_local/csad_equip.py +0 -0
  44. {python_omnilogic_local-0.20.6 → python_omnilogic_local-0.20.8}/pyomnilogic_local/decorators.py +0 -0
  45. {python_omnilogic_local-0.20.6 → python_omnilogic_local-0.20.8}/pyomnilogic_local/filter.py +0 -0
  46. {python_omnilogic_local-0.20.6 → python_omnilogic_local-0.20.8}/pyomnilogic_local/groups.py +0 -0
  47. {python_omnilogic_local-0.20.6 → python_omnilogic_local-0.20.8}/pyomnilogic_local/heater.py +0 -0
  48. {python_omnilogic_local-0.20.6 → python_omnilogic_local-0.20.8}/pyomnilogic_local/heater_equip.py +0 -0
  49. {python_omnilogic_local-0.20.6 → python_omnilogic_local-0.20.8}/pyomnilogic_local/models/__init__.py +0 -0
  50. {python_omnilogic_local-0.20.6 → python_omnilogic_local-0.20.8}/pyomnilogic_local/models/const.py +0 -0
  51. {python_omnilogic_local-0.20.6 → python_omnilogic_local-0.20.8}/pyomnilogic_local/models/exceptions.py +0 -0
  52. {python_omnilogic_local-0.20.6 → python_omnilogic_local-0.20.8}/pyomnilogic_local/models/filter_diagnostics.py +0 -0
  53. {python_omnilogic_local-0.20.6 → python_omnilogic_local-0.20.8}/pyomnilogic_local/models/leadmessage.py +0 -0
  54. {python_omnilogic_local-0.20.6 → python_omnilogic_local-0.20.8}/pyomnilogic_local/omnitypes.py +0 -0
  55. {python_omnilogic_local-0.20.6 → python_omnilogic_local-0.20.8}/pyomnilogic_local/pump.py +0 -0
  56. {python_omnilogic_local-0.20.6 → python_omnilogic_local-0.20.8}/pyomnilogic_local/py.typed +0 -0
  57. {python_omnilogic_local-0.20.6 → python_omnilogic_local-0.20.8}/pyomnilogic_local/relay.py +0 -0
  58. {python_omnilogic_local-0.20.6 → python_omnilogic_local-0.20.8}/pyomnilogic_local/schedule.py +0 -0
  59. {python_omnilogic_local-0.20.6 → python_omnilogic_local-0.20.8}/pyomnilogic_local/sensor.py +0 -0
  60. {python_omnilogic_local-0.20.6 → python_omnilogic_local-0.20.8}/pyomnilogic_local/system.py +0 -0
  61. {python_omnilogic_local-0.20.6 → python_omnilogic_local-0.20.8}/pyomnilogic_local/util.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-omnilogic-local
3
- Version: 0.20.6
3
+ Version: 0.20.8
4
4
  Summary: A library for local control of Hayward OmniHub/OmniLogic pool controllers using their local API
5
5
  Author: Chris Jowett, djtimca, garionphx
6
6
  Author-email: Chris Jowett <421501+cryptk@users.noreply.github.com>
@@ -20,9 +20,9 @@ Description-Content-Type: text/markdown
20
20
  # Python OmniLogic Local
21
21
 
22
22
  [![PyPI Version](https://img.shields.io/pypi/v/python-omnilogic-local.svg?logo=python&logoColor=fff&style=flat-square)](https://pypi.org/project/python-omnilogic-local/)
23
- [![Python Versions](https://img.shields.io/pypi/pyversions/python-omnilogic-local.svg?style=flat-square&logo=python&logoColor=fff)](https://pypi.org/project/python-omnilogic-local/)
24
- [![Build Status](https://img.shields.io/github/actions/workflow/status/cryptk/python-omnilogic-local/build-test.yml?style=flat-square&label=Build)](https://github.com/cryptk/python-omnilogic-local/actions)
25
- [![License](https://img.shields.io/pypi/l/python-omnilogic-local.svg?style=flat-square)](LICENSE)
23
+ ![Python Version](https://img.shields.io/python/required-version-toml?tomlFilePath=https%3A%2F%2Fraw.githubusercontent.com%2Fcryptk%2Fpython-omnilogic-local%2Frefs%2Fheads%2Fmain%2Fpyproject.toml?style=flat-square)
24
+ [![Tests](https://img.shields.io/github/actions/workflow/status/cryptk/python-omnilogic-local/ci-testing.yml?style=flat-square&label=Tests)](https://github.com/cryptk/python-omnilogic-local/actions)
25
+ [![License](https://img.shields.io/github/license/cryptk/python-omnilogic-local?style=flat-square)](LICENSE)
26
26
  [![Buy Me A Coffee](https://img.shields.io/badge/Buy_Me_A_Coffee-FFDD00?style=flat-square&logo=buy-me-a-coffee&logoColor=000)](https://www.buymeacoffee.com/cryptk)
27
27
 
28
28
  **A modern Python library for local control of Hayward OmniLogic and OmniHub pool controllers**
@@ -3,9 +3,9 @@
3
3
  # Python OmniLogic Local
4
4
 
5
5
  [![PyPI Version](https://img.shields.io/pypi/v/python-omnilogic-local.svg?logo=python&logoColor=fff&style=flat-square)](https://pypi.org/project/python-omnilogic-local/)
6
- [![Python Versions](https://img.shields.io/pypi/pyversions/python-omnilogic-local.svg?style=flat-square&logo=python&logoColor=fff)](https://pypi.org/project/python-omnilogic-local/)
7
- [![Build Status](https://img.shields.io/github/actions/workflow/status/cryptk/python-omnilogic-local/build-test.yml?style=flat-square&label=Build)](https://github.com/cryptk/python-omnilogic-local/actions)
8
- [![License](https://img.shields.io/pypi/l/python-omnilogic-local.svg?style=flat-square)](LICENSE)
6
+ ![Python Version](https://img.shields.io/python/required-version-toml?tomlFilePath=https%3A%2F%2Fraw.githubusercontent.com%2Fcryptk%2Fpython-omnilogic-local%2Frefs%2Fheads%2Fmain%2Fpyproject.toml?style=flat-square)
7
+ [![Tests](https://img.shields.io/github/actions/workflow/status/cryptk/python-omnilogic-local/ci-testing.yml?style=flat-square&label=Tests)](https://github.com/cryptk/python-omnilogic-local/actions)
8
+ [![License](https://img.shields.io/github/license/cryptk/python-omnilogic-local?style=flat-square)](LICENSE)
9
9
  [![Buy Me A Coffee](https://img.shields.io/badge/Buy_Me_A_Coffee-FFDD00?style=flat-square&logo=buy-me-a-coffee&logoColor=000)](https://www.buymeacoffee.com/cryptk)
10
10
 
11
11
  **A modern Python library for local control of Hayward OmniLogic and OmniHub pool controllers**
@@ -229,7 +229,12 @@ class OmniLogicProtocol(asyncio.DatagramProtocol):
229
229
  # Wait for either a message or an error
230
230
  data_task = asyncio.create_task(self.data_queue.get())
231
231
  error_task = asyncio.create_task(self.error_queue.get())
232
- done, _ = await asyncio.wait([data_task, error_task], return_when=asyncio.FIRST_COMPLETED)
232
+ done, pending = await asyncio.wait([data_task, error_task], return_when=asyncio.FIRST_COMPLETED)
233
+
234
+ # Cancel any pending tasks to avoid "Task was destroyed but it is pending" warnings
235
+ for task in pending:
236
+ task.cancel()
237
+
233
238
  if error_task in done:
234
239
  exc = error_task.result()
235
240
  if isinstance(exc, Exception):
@@ -168,7 +168,7 @@ class ColorLogicLight(OmniEquipment[MSPColorLogicLight, TelemetryColorLogicLight
168
168
  @property
169
169
  def show(self) -> LightShows:
170
170
  """Returns the current light show."""
171
- return self.telemetry.show
171
+ return self.telemetry.show_name(self.model, self.v2_active)
172
172
 
173
173
  @property
174
174
  def speed(self) -> ColorLogicSpeed:
@@ -282,7 +282,7 @@ class ColorLogicLight(OmniEquipment[MSPColorLogicLight, TelemetryColorLogicLight
282
282
  await self._api.async_set_light_show(
283
283
  self.bow_id,
284
284
  self.system_id,
285
- show or self.show, # use current value if None
286
- speed or self.speed, # use current value if None
287
- brightness or self.brightness, # use current value if None
285
+ show if show is not None else self.show, # use current value if None
286
+ speed if speed is not None else self.speed, # use current value if None
287
+ brightness if brightness is not None else self.brightness, # use current value if None
288
288
  )
@@ -289,14 +289,13 @@ class MSPColorLogicLight(OmniBase):
289
289
 
290
290
  omni_type: OmniType = OmniType.CL_LIGHT
291
291
 
292
- equip_type: ColorLogicLightType = Field(alias="Type")
293
292
  v2_active: bool = Field(alias="V2-Active", default=False)
293
+ equip_type: ColorLogicLightType = Field(alias="Type")
294
294
  effects: list[LightShows] | None = None
295
295
 
296
- def __init__(self, **data: Any) -> None:
297
- super().__init__(**data)
298
-
299
- # Get the available light shows depending on the light type.
296
+ @model_validator(mode="after")
297
+ def set_effects(self) -> Any:
298
+ """Set the available light shows based on the light type."""
300
299
  match self.equip_type:
301
300
  case ColorLogicLightType.TWO_FIVE:
302
301
  self.effects = list(ColorLogicShow25)
@@ -311,6 +310,7 @@ class MSPColorLogicLight(OmniBase):
311
310
  self.effects = list(PentairShow)
312
311
  case ColorLogicLightType.ZODIAC_COLOR:
313
312
  self.effects = list(ZodiacShow)
313
+ return self
314
314
 
315
315
 
316
316
  class MSPGroup(OmniBase):
@@ -267,7 +267,7 @@ class TelemetryColorLogicLight(BaseModel):
267
267
 
268
268
  def show_name(
269
269
  self, model: ColorLogicLightType, v2: bool
270
- ) -> ColorLogicShow25 | ColorLogicShow40 | ColorLogicShowUCL | ColorLogicShowUCLV2 | PentairShow | ZodiacShow | int:
270
+ ) -> ColorLogicShow25 | ColorLogicShow40 | ColorLogicShowUCL | ColorLogicShowUCLV2 | PentairShow | ZodiacShow:
271
271
  """Get the current light show depending on the light type.
272
272
 
273
273
  Returns:
@@ -287,7 +287,8 @@ class TelemetryColorLogicLight(BaseModel):
287
287
  return PentairShow(self.show)
288
288
  case ColorLogicLightType.ZODIAC_COLOR:
289
289
  return ZodiacShow(self.show)
290
- return self.show # Return raw int if type is unknown
290
+ msg = f"Unknown ColorLogicLightType {model} for show name parsing"
291
+ raise OmniParsingError(msg)
291
292
 
292
293
 
293
294
  class TelemetryFilter(BaseModel):
@@ -15,6 +15,7 @@ from pyomnilogic_local.system import System
15
15
 
16
16
  if TYPE_CHECKING:
17
17
  from pyomnilogic_local._base import OmniEquipment
18
+ from pyomnilogic_local.bow import Bow
18
19
  from pyomnilogic_local.chlorinator import Chlorinator
19
20
  from pyomnilogic_local.chlorinator_equip import ChlorinatorEquipment
20
21
  from pyomnilogic_local.colorlogiclight import ColorLogicLight
@@ -260,6 +261,12 @@ class OmniLogic:
260
261
  csads.extend(bow.csads.values())
261
262
  return EquipmentDict(csads)
262
263
 
264
+ @property
265
+ def all_bows(self) -> EquipmentDict[Bow]:
266
+ """Returns all Bow instances across all bows in the backyard."""
267
+ # Bows are stored directly in backyard as EquipmentDict already
268
+ return self.backyard.bow
269
+
263
270
  # Equipment search methods
264
271
  def get_equipment_by_name(self, name: str) -> OmniEquipment[Any, Any] | None:
265
272
  """Find equipment by name across all equipment types.
@@ -272,6 +279,7 @@ class OmniLogic:
272
279
  """
273
280
  # Search all equipment types
274
281
  all_equipment: list[OmniEquipment[Any, Any]] = []
282
+ all_equipment.extend([self.backyard])
275
283
  all_equipment.extend(self.all_lights.values())
276
284
  all_equipment.extend(self.all_relays.values())
277
285
  all_equipment.extend(self.all_pumps.values())
@@ -283,6 +291,7 @@ class OmniLogic:
283
291
  all_equipment.extend(self.all_chlorinator_equipment.values())
284
292
  all_equipment.extend(self.all_csads.values())
285
293
  all_equipment.extend(self.all_csad_equipment.values())
294
+ all_equipment.extend(self.all_bows.values())
286
295
  all_equipment.extend(self.groups.values())
287
296
 
288
297
  for equipment in all_equipment:
@@ -302,6 +311,7 @@ class OmniLogic:
302
311
  """
303
312
  # Search all equipment types
304
313
  all_equipment: list[OmniEquipment[Any, Any]] = []
314
+ all_equipment.extend([self.backyard])
305
315
  all_equipment.extend(self.all_lights.values())
306
316
  all_equipment.extend(self.all_relays.values())
307
317
  all_equipment.extend(self.all_pumps.values())
@@ -313,6 +323,7 @@ class OmniLogic:
313
323
  all_equipment.extend(self.all_chlorinator_equipment.values())
314
324
  all_equipment.extend(self.all_csads.values())
315
325
  all_equipment.extend(self.all_csad_equipment.values())
326
+ all_equipment.extend(self.all_bows.values())
316
327
  all_equipment.extend(self.groups.values())
317
328
  all_equipment.extend(self.schedules.values())
318
329
 
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "python-omnilogic-local"
3
- version = "0.20.6"
3
+ version = "0.20.8"
4
4
  description = "A library for local control of Hayward OmniHub/OmniLogic pool controllers using their local API"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.13,<4.0.0"
@@ -47,7 +47,7 @@ python_version = "3.13"
47
47
  plugins = [
48
48
  "pydantic.mypy"
49
49
  ]
50
- follow_imports = "silent"
50
+ # follow_imports = "silent"
51
51
  strict = true
52
52
  ignore_missing_imports = true
53
53
  disallow_subclassing_any = false