python-omnilogic-local 2.3.0__tar.gz → 2.4.0__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 (63) hide show
  1. {python_omnilogic_local-2.3.0 → python_omnilogic_local-2.4.0}/PKG-INFO +1 -1
  2. {python_omnilogic_local-2.3.0 → python_omnilogic_local-2.4.0}/pyomnilogic_local/cli/debug/commands.py +20 -0
  3. {python_omnilogic_local-2.3.0 → python_omnilogic_local-2.4.0}/pyomnilogic_local/filter.py +36 -1
  4. {python_omnilogic_local-2.3.0 → python_omnilogic_local-2.4.0}/pyomnilogic_local/omnitypes.py +1 -0
  5. {python_omnilogic_local-2.3.0 → python_omnilogic_local-2.4.0}/pyomnilogic_local/pump.py +34 -0
  6. {python_omnilogic_local-2.3.0 → python_omnilogic_local-2.4.0}/pyproject.toml +1 -1
  7. {python_omnilogic_local-2.3.0 → python_omnilogic_local-2.4.0}/LICENSE +0 -0
  8. {python_omnilogic_local-2.3.0 → python_omnilogic_local-2.4.0}/README.md +0 -0
  9. {python_omnilogic_local-2.3.0 → python_omnilogic_local-2.4.0}/pyomnilogic_local/__init__.py +0 -0
  10. {python_omnilogic_local-2.3.0 → python_omnilogic_local-2.4.0}/pyomnilogic_local/_base.py +0 -0
  11. {python_omnilogic_local-2.3.0 → python_omnilogic_local-2.4.0}/pyomnilogic_local/api/__init__.py +0 -0
  12. {python_omnilogic_local-2.3.0 → python_omnilogic_local-2.4.0}/pyomnilogic_local/api/api.py +0 -0
  13. {python_omnilogic_local-2.3.0 → python_omnilogic_local-2.4.0}/pyomnilogic_local/api/constants.py +0 -0
  14. {python_omnilogic_local-2.3.0 → python_omnilogic_local-2.4.0}/pyomnilogic_local/api/exceptions.py +0 -0
  15. {python_omnilogic_local-2.3.0 → python_omnilogic_local-2.4.0}/pyomnilogic_local/api/message.py +0 -0
  16. {python_omnilogic_local-2.3.0 → python_omnilogic_local-2.4.0}/pyomnilogic_local/api/mock_api.py +0 -0
  17. {python_omnilogic_local-2.3.0 → python_omnilogic_local-2.4.0}/pyomnilogic_local/api/protocol.py +0 -0
  18. {python_omnilogic_local-2.3.0 → python_omnilogic_local-2.4.0}/pyomnilogic_local/backyard.py +0 -0
  19. {python_omnilogic_local-2.3.0 → python_omnilogic_local-2.4.0}/pyomnilogic_local/bow.py +0 -0
  20. {python_omnilogic_local-2.3.0 → python_omnilogic_local-2.4.0}/pyomnilogic_local/chlorinator.py +0 -0
  21. {python_omnilogic_local-2.3.0 → python_omnilogic_local-2.4.0}/pyomnilogic_local/chlorinator_equip.py +0 -0
  22. {python_omnilogic_local-2.3.0 → python_omnilogic_local-2.4.0}/pyomnilogic_local/cli/__init__.py +0 -0
  23. {python_omnilogic_local-2.3.0 → python_omnilogic_local-2.4.0}/pyomnilogic_local/cli/cli.py +0 -0
  24. {python_omnilogic_local-2.3.0 → python_omnilogic_local-2.4.0}/pyomnilogic_local/cli/debug/__init__.py +0 -0
  25. {python_omnilogic_local-2.3.0 → python_omnilogic_local-2.4.0}/pyomnilogic_local/cli/get/__init__.py +0 -0
  26. {python_omnilogic_local-2.3.0 → python_omnilogic_local-2.4.0}/pyomnilogic_local/cli/get/backyard.py +0 -0
  27. {python_omnilogic_local-2.3.0 → python_omnilogic_local-2.4.0}/pyomnilogic_local/cli/get/bows.py +0 -0
  28. {python_omnilogic_local-2.3.0 → python_omnilogic_local-2.4.0}/pyomnilogic_local/cli/get/chlorinators.py +0 -0
  29. {python_omnilogic_local-2.3.0 → python_omnilogic_local-2.4.0}/pyomnilogic_local/cli/get/commands.py +0 -0
  30. {python_omnilogic_local-2.3.0 → python_omnilogic_local-2.4.0}/pyomnilogic_local/cli/get/csads.py +0 -0
  31. {python_omnilogic_local-2.3.0 → python_omnilogic_local-2.4.0}/pyomnilogic_local/cli/get/filters.py +0 -0
  32. {python_omnilogic_local-2.3.0 → python_omnilogic_local-2.4.0}/pyomnilogic_local/cli/get/groups.py +0 -0
  33. {python_omnilogic_local-2.3.0 → python_omnilogic_local-2.4.0}/pyomnilogic_local/cli/get/heaters.py +0 -0
  34. {python_omnilogic_local-2.3.0 → python_omnilogic_local-2.4.0}/pyomnilogic_local/cli/get/lights.py +0 -0
  35. {python_omnilogic_local-2.3.0 → python_omnilogic_local-2.4.0}/pyomnilogic_local/cli/get/pumps.py +0 -0
  36. {python_omnilogic_local-2.3.0 → python_omnilogic_local-2.4.0}/pyomnilogic_local/cli/get/relays.py +0 -0
  37. {python_omnilogic_local-2.3.0 → python_omnilogic_local-2.4.0}/pyomnilogic_local/cli/get/schedules.py +0 -0
  38. {python_omnilogic_local-2.3.0 → python_omnilogic_local-2.4.0}/pyomnilogic_local/cli/get/sensors.py +0 -0
  39. {python_omnilogic_local-2.3.0 → python_omnilogic_local-2.4.0}/pyomnilogic_local/cli/get/valves.py +0 -0
  40. {python_omnilogic_local-2.3.0 → python_omnilogic_local-2.4.0}/pyomnilogic_local/cli/pcap_utils.py +0 -0
  41. {python_omnilogic_local-2.3.0 → python_omnilogic_local-2.4.0}/pyomnilogic_local/cli/utils.py +0 -0
  42. {python_omnilogic_local-2.3.0 → python_omnilogic_local-2.4.0}/pyomnilogic_local/collections.py +0 -0
  43. {python_omnilogic_local-2.3.0 → python_omnilogic_local-2.4.0}/pyomnilogic_local/colorlogiclight.py +0 -0
  44. {python_omnilogic_local-2.3.0 → python_omnilogic_local-2.4.0}/pyomnilogic_local/csad.py +0 -0
  45. {python_omnilogic_local-2.3.0 → python_omnilogic_local-2.4.0}/pyomnilogic_local/csad_equip.py +0 -0
  46. {python_omnilogic_local-2.3.0 → python_omnilogic_local-2.4.0}/pyomnilogic_local/decorators.py +0 -0
  47. {python_omnilogic_local-2.3.0 → python_omnilogic_local-2.4.0}/pyomnilogic_local/groups.py +0 -0
  48. {python_omnilogic_local-2.3.0 → python_omnilogic_local-2.4.0}/pyomnilogic_local/heater.py +0 -0
  49. {python_omnilogic_local-2.3.0 → python_omnilogic_local-2.4.0}/pyomnilogic_local/heater_equip.py +0 -0
  50. {python_omnilogic_local-2.3.0 → python_omnilogic_local-2.4.0}/pyomnilogic_local/models/__init__.py +0 -0
  51. {python_omnilogic_local-2.3.0 → python_omnilogic_local-2.4.0}/pyomnilogic_local/models/const.py +0 -0
  52. {python_omnilogic_local-2.3.0 → python_omnilogic_local-2.4.0}/pyomnilogic_local/models/exceptions.py +0 -0
  53. {python_omnilogic_local-2.3.0 → python_omnilogic_local-2.4.0}/pyomnilogic_local/models/filter_diagnostics.py +0 -0
  54. {python_omnilogic_local-2.3.0 → python_omnilogic_local-2.4.0}/pyomnilogic_local/models/leadmessage.py +0 -0
  55. {python_omnilogic_local-2.3.0 → python_omnilogic_local-2.4.0}/pyomnilogic_local/models/mspconfig.py +0 -0
  56. {python_omnilogic_local-2.3.0 → python_omnilogic_local-2.4.0}/pyomnilogic_local/models/telemetry.py +0 -0
  57. {python_omnilogic_local-2.3.0 → python_omnilogic_local-2.4.0}/pyomnilogic_local/omnilogic.py +0 -0
  58. {python_omnilogic_local-2.3.0 → python_omnilogic_local-2.4.0}/pyomnilogic_local/py.typed +0 -0
  59. {python_omnilogic_local-2.3.0 → python_omnilogic_local-2.4.0}/pyomnilogic_local/relay.py +0 -0
  60. {python_omnilogic_local-2.3.0 → python_omnilogic_local-2.4.0}/pyomnilogic_local/schedule.py +0 -0
  61. {python_omnilogic_local-2.3.0 → python_omnilogic_local-2.4.0}/pyomnilogic_local/sensor.py +0 -0
  62. {python_omnilogic_local-2.3.0 → python_omnilogic_local-2.4.0}/pyomnilogic_local/system.py +0 -0
  63. {python_omnilogic_local-2.3.0 → python_omnilogic_local-2.4.0}/pyomnilogic_local/util.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-omnilogic-local
3
- Version: 2.3.0
3
+ Version: 2.4.0
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>
@@ -71,6 +71,26 @@ def get_telemetry(ctx: click.Context) -> None:
71
71
  click.echo(telemetry)
72
72
 
73
73
 
74
+ @debug.command()
75
+ @click.argument("bow_id", type=int)
76
+ @click.argument("equip_id", type=int)
77
+ @click.pass_context
78
+ def get_filter_diagnostics(ctx: click.Context, bow_id: int, equip_id: int) -> None:
79
+ """Retrieve current filter diagnostics from the controller.
80
+
81
+ Filter diagnostics include real-time sensor readings, equipment states, temperatures,
82
+ and other operational data. Use --raw to see the unprocessed XML.
83
+
84
+ Example:
85
+ omnilogic debug get-filter-diagnostics
86
+ omnilogic debug --raw get-filter-diagnostics
87
+
88
+ """
89
+ omnilogic: OmniLogic = ctx.obj["OMNILOGIC"]
90
+ telemetry = asyncio.run(omnilogic._api.async_get_filter_diagnostics(pool_id=bow_id, equipment_id=equip_id, raw=ctx.obj["RAW"]))
91
+ click.echo(telemetry)
92
+
93
+
74
94
  @debug.command()
75
95
  @click.argument("pcap_file", type=click.Path(exists=True, path_type=Path))
76
96
  def parse_pcap(pcap_file: Path) -> None:
@@ -223,7 +223,8 @@ class Filter(OmniEquipment[MSPFilter, TelemetryFilter]):
223
223
  # This matches the behavior of the OmniLogic phone app
224
224
  target_speed: int = 100
225
225
  match self.equip_type:
226
- case FilterType.VARIABLE_SPEED:
226
+ # Dual speed filters are controlled similar to VSPs, but they only support speed values of 0, 50, and 100
227
+ case FilterType.VARIABLE_SPEED | FilterType.DUAL_SPEED:
227
228
  if self.last_speed >= self.min_percent and self.last_speed <= self.max_percent:
228
229
  target_speed = self.last_speed
229
230
  case FilterType.SINGLE_SPEED:
@@ -310,3 +311,37 @@ class Filter(OmniEquipment[MSPFilter, TelemetryFilter]):
310
311
  equipment_id=self.system_id,
311
312
  speed=speed,
312
313
  )
314
+
315
+ @control_method
316
+ async def set_dual_speed(self, speed: FilterSpeedPresets) -> None:
317
+ """Set the filter to a specific speed for dual speed filters.
318
+
319
+ For Dual Speed filters, LOW and MEDIUM presets will set the filter to 50% speed, while HIGH will set it to 100%.
320
+ Semantically, it is preferred to only use LOW and HIGH presets for dual speed filters but MEDIUM is accepted for convenience
321
+
322
+ Args:
323
+ speed: The preset speed to use (LOW, or HIGH)
324
+
325
+ Raises:
326
+ OmniEquipmentNotInitializedError: If bow_id or system_id is None.
327
+ ValueError: If an invalid speed preset is provided or if the filter is not a dual speed filter.
328
+ """
329
+ if self.equip_type != FilterType.DUAL_SPEED:
330
+ msg = "set_dual_speed can only be used with dual speed filters"
331
+ raise ValueError(msg)
332
+
333
+ if self.bow_id is None or self.system_id is None:
334
+ msg = "Filter bow_id and system_id must be set"
335
+ raise OmniEquipmentNotInitializedError(msg)
336
+
337
+ speed_value: int
338
+ match speed:
339
+ case FilterSpeedPresets.LOW | FilterSpeedPresets.MEDIUM:
340
+ speed_value = 50
341
+ case FilterSpeedPresets.HIGH:
342
+ speed_value = 100
343
+ case _:
344
+ msg = f"Invalid speed preset: {speed}"
345
+ raise ValueError(msg)
346
+
347
+ await self.set_speed(speed_value)
@@ -35,6 +35,7 @@ class MessageType(PrettyEnum, IntEnum):
35
35
  MSP_CONFIGURATIONUPDATE = 1003
36
36
  MSP_TELEMETRY_UPDATE = 1004
37
37
  MSP_ALARM_LIST_RESPONSE = 1304
38
+ MSP_FILTER_DIAGNOSTIC_INFO_RESPONSE = 1386
38
39
  MSP_LEADMESSAGE = 1998
39
40
  MSP_BLOCKMESSAGE = 1999
40
41
 
@@ -291,3 +291,37 @@ class Pump(OmniEquipment[MSPPump, TelemetryPump]):
291
291
  equipment_id=self.system_id,
292
292
  is_on=speed,
293
293
  )
294
+
295
+ @control_method
296
+ async def set_dual_speed(self, speed: PumpSpeedPresets) -> None:
297
+ """Set the pump to a specific speed for dual speed pumps.
298
+
299
+ For Dual Speed pumps, LOW and MEDIUM presets will set the pump to 50% speed, while HIGH will set it to 100%.
300
+ Semantically, it is preferred to only use LOW and HIGH presets for dual speed pumps but MEDIUM is accepted for convenience
301
+
302
+ Args:
303
+ speed: The preset speed to use (LOW, or HIGH)
304
+
305
+ Raises:
306
+ OmniEquipmentNotInitializedError: If bow_id or system_id is None.
307
+ ValueError: If an invalid speed preset is provided or if the pump is not a dual speed pump.
308
+ """
309
+ if self.equip_type != PumpType.DUAL_SPEED:
310
+ msg = "set_dual_speed can only be used with dual speed pumps"
311
+ raise ValueError(msg)
312
+
313
+ if self.bow_id is None or self.system_id is None:
314
+ msg = "Pump bow_id and system_id must be set"
315
+ raise OmniEquipmentNotInitializedError(msg)
316
+
317
+ speed_value: int
318
+ match speed:
319
+ case PumpSpeedPresets.LOW | PumpSpeedPresets.MEDIUM:
320
+ speed_value = 50
321
+ case PumpSpeedPresets.HIGH:
322
+ speed_value = 100
323
+ case _:
324
+ msg = f"Invalid speed preset: {speed}"
325
+ raise ValueError(msg)
326
+
327
+ await self.set_speed(speed_value)
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "python-omnilogic-local"
3
- version = "2.3.0"
3
+ version = "2.4.0"
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.14.2"