python-omnilogic-local 0.26.0__tar.gz → 0.27.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 (62) hide show
  1. {python_omnilogic_local-0.26.0 → python_omnilogic_local-0.27.0}/PKG-INFO +1 -1
  2. {python_omnilogic_local-0.26.0 → python_omnilogic_local-0.27.0}/pyomnilogic_local/api/mock_api.py +8 -2
  3. {python_omnilogic_local-0.26.0 → python_omnilogic_local-0.27.0}/pyomnilogic_local/models/filter_diagnostics.py +12 -2
  4. {python_omnilogic_local-0.26.0 → python_omnilogic_local-0.27.0}/pyomnilogic_local/models/leadmessage.py +1 -1
  5. {python_omnilogic_local-0.26.0 → python_omnilogic_local-0.27.0}/pyomnilogic_local/models/mspconfig.py +6 -1
  6. {python_omnilogic_local-0.26.0 → python_omnilogic_local-0.27.0}/pyomnilogic_local/models/telemetry.py +7 -3
  7. {python_omnilogic_local-0.26.0 → python_omnilogic_local-0.27.0}/pyproject.toml +3 -8
  8. {python_omnilogic_local-0.26.0 → python_omnilogic_local-0.27.0}/LICENSE +0 -0
  9. {python_omnilogic_local-0.26.0 → python_omnilogic_local-0.27.0}/README.md +0 -0
  10. {python_omnilogic_local-0.26.0 → python_omnilogic_local-0.27.0}/pyomnilogic_local/__init__.py +0 -0
  11. {python_omnilogic_local-0.26.0 → python_omnilogic_local-0.27.0}/pyomnilogic_local/_base.py +0 -0
  12. {python_omnilogic_local-0.26.0 → python_omnilogic_local-0.27.0}/pyomnilogic_local/api/__init__.py +0 -0
  13. {python_omnilogic_local-0.26.0 → python_omnilogic_local-0.27.0}/pyomnilogic_local/api/api.py +0 -0
  14. {python_omnilogic_local-0.26.0 → python_omnilogic_local-0.27.0}/pyomnilogic_local/api/constants.py +0 -0
  15. {python_omnilogic_local-0.26.0 → python_omnilogic_local-0.27.0}/pyomnilogic_local/api/exceptions.py +0 -0
  16. {python_omnilogic_local-0.26.0 → python_omnilogic_local-0.27.0}/pyomnilogic_local/api/protocol.py +0 -0
  17. {python_omnilogic_local-0.26.0 → python_omnilogic_local-0.27.0}/pyomnilogic_local/backyard.py +0 -0
  18. {python_omnilogic_local-0.26.0 → python_omnilogic_local-0.27.0}/pyomnilogic_local/bow.py +0 -0
  19. {python_omnilogic_local-0.26.0 → python_omnilogic_local-0.27.0}/pyomnilogic_local/chlorinator.py +0 -0
  20. {python_omnilogic_local-0.26.0 → python_omnilogic_local-0.27.0}/pyomnilogic_local/chlorinator_equip.py +0 -0
  21. {python_omnilogic_local-0.26.0 → python_omnilogic_local-0.27.0}/pyomnilogic_local/cli/__init__.py +0 -0
  22. {python_omnilogic_local-0.26.0 → python_omnilogic_local-0.27.0}/pyomnilogic_local/cli/cli.py +0 -0
  23. {python_omnilogic_local-0.26.0 → python_omnilogic_local-0.27.0}/pyomnilogic_local/cli/debug/__init__.py +0 -0
  24. {python_omnilogic_local-0.26.0 → python_omnilogic_local-0.27.0}/pyomnilogic_local/cli/debug/commands.py +0 -0
  25. {python_omnilogic_local-0.26.0 → python_omnilogic_local-0.27.0}/pyomnilogic_local/cli/get/__init__.py +0 -0
  26. {python_omnilogic_local-0.26.0 → python_omnilogic_local-0.27.0}/pyomnilogic_local/cli/get/backyard.py +0 -0
  27. {python_omnilogic_local-0.26.0 → python_omnilogic_local-0.27.0}/pyomnilogic_local/cli/get/bows.py +0 -0
  28. {python_omnilogic_local-0.26.0 → python_omnilogic_local-0.27.0}/pyomnilogic_local/cli/get/chlorinators.py +0 -0
  29. {python_omnilogic_local-0.26.0 → python_omnilogic_local-0.27.0}/pyomnilogic_local/cli/get/commands.py +0 -0
  30. {python_omnilogic_local-0.26.0 → python_omnilogic_local-0.27.0}/pyomnilogic_local/cli/get/csads.py +0 -0
  31. {python_omnilogic_local-0.26.0 → python_omnilogic_local-0.27.0}/pyomnilogic_local/cli/get/filters.py +0 -0
  32. {python_omnilogic_local-0.26.0 → python_omnilogic_local-0.27.0}/pyomnilogic_local/cli/get/groups.py +0 -0
  33. {python_omnilogic_local-0.26.0 → python_omnilogic_local-0.27.0}/pyomnilogic_local/cli/get/heaters.py +0 -0
  34. {python_omnilogic_local-0.26.0 → python_omnilogic_local-0.27.0}/pyomnilogic_local/cli/get/lights.py +0 -0
  35. {python_omnilogic_local-0.26.0 → python_omnilogic_local-0.27.0}/pyomnilogic_local/cli/get/pumps.py +0 -0
  36. {python_omnilogic_local-0.26.0 → python_omnilogic_local-0.27.0}/pyomnilogic_local/cli/get/relays.py +0 -0
  37. {python_omnilogic_local-0.26.0 → python_omnilogic_local-0.27.0}/pyomnilogic_local/cli/get/schedules.py +0 -0
  38. {python_omnilogic_local-0.26.0 → python_omnilogic_local-0.27.0}/pyomnilogic_local/cli/get/sensors.py +0 -0
  39. {python_omnilogic_local-0.26.0 → python_omnilogic_local-0.27.0}/pyomnilogic_local/cli/get/valves.py +0 -0
  40. {python_omnilogic_local-0.26.0 → python_omnilogic_local-0.27.0}/pyomnilogic_local/cli/pcap_utils.py +0 -0
  41. {python_omnilogic_local-0.26.0 → python_omnilogic_local-0.27.0}/pyomnilogic_local/cli/utils.py +0 -0
  42. {python_omnilogic_local-0.26.0 → python_omnilogic_local-0.27.0}/pyomnilogic_local/collections.py +0 -0
  43. {python_omnilogic_local-0.26.0 → python_omnilogic_local-0.27.0}/pyomnilogic_local/colorlogiclight.py +0 -0
  44. {python_omnilogic_local-0.26.0 → python_omnilogic_local-0.27.0}/pyomnilogic_local/csad.py +0 -0
  45. {python_omnilogic_local-0.26.0 → python_omnilogic_local-0.27.0}/pyomnilogic_local/csad_equip.py +0 -0
  46. {python_omnilogic_local-0.26.0 → python_omnilogic_local-0.27.0}/pyomnilogic_local/decorators.py +0 -0
  47. {python_omnilogic_local-0.26.0 → python_omnilogic_local-0.27.0}/pyomnilogic_local/filter.py +0 -0
  48. {python_omnilogic_local-0.26.0 → python_omnilogic_local-0.27.0}/pyomnilogic_local/groups.py +0 -0
  49. {python_omnilogic_local-0.26.0 → python_omnilogic_local-0.27.0}/pyomnilogic_local/heater.py +0 -0
  50. {python_omnilogic_local-0.26.0 → python_omnilogic_local-0.27.0}/pyomnilogic_local/heater_equip.py +0 -0
  51. {python_omnilogic_local-0.26.0 → python_omnilogic_local-0.27.0}/pyomnilogic_local/models/__init__.py +0 -0
  52. {python_omnilogic_local-0.26.0 → python_omnilogic_local-0.27.0}/pyomnilogic_local/models/const.py +0 -0
  53. {python_omnilogic_local-0.26.0 → python_omnilogic_local-0.27.0}/pyomnilogic_local/models/exceptions.py +0 -0
  54. {python_omnilogic_local-0.26.0 → python_omnilogic_local-0.27.0}/pyomnilogic_local/omnilogic.py +0 -0
  55. {python_omnilogic_local-0.26.0 → python_omnilogic_local-0.27.0}/pyomnilogic_local/omnitypes.py +0 -0
  56. {python_omnilogic_local-0.26.0 → python_omnilogic_local-0.27.0}/pyomnilogic_local/pump.py +0 -0
  57. {python_omnilogic_local-0.26.0 → python_omnilogic_local-0.27.0}/pyomnilogic_local/py.typed +0 -0
  58. {python_omnilogic_local-0.26.0 → python_omnilogic_local-0.27.0}/pyomnilogic_local/relay.py +0 -0
  59. {python_omnilogic_local-0.26.0 → python_omnilogic_local-0.27.0}/pyomnilogic_local/schedule.py +0 -0
  60. {python_omnilogic_local-0.26.0 → python_omnilogic_local-0.27.0}/pyomnilogic_local/sensor.py +0 -0
  61. {python_omnilogic_local-0.26.0 → python_omnilogic_local-0.27.0}/pyomnilogic_local/system.py +0 -0
  62. {python_omnilogic_local-0.26.0 → python_omnilogic_local-0.27.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: 0.26.0
3
+ Version: 0.27.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>
@@ -5,7 +5,7 @@ from __future__ import annotations
5
5
  import json
6
6
  import logging
7
7
  from pathlib import Path
8
- from typing import Any, Literal, overload
8
+ from typing import Any, Literal, TypedDict, overload
9
9
 
10
10
  from pyomnilogic_local.models.mspconfig import MSPConfig
11
11
  from pyomnilogic_local.models.telemetry import Telemetry
@@ -13,6 +13,12 @@ from pyomnilogic_local.models.telemetry import Telemetry
13
13
  _LOGGER = logging.getLogger(__name__)
14
14
 
15
15
 
16
+ class SimData(TypedDict):
17
+ telemetry: str
18
+ msp_config: str
19
+ filepath: str
20
+
21
+
16
22
  class OmniLogicMockAPI:
17
23
  """Drop-in replacement for OmniLogicAPI that serves pre-recorded data from one or more JSON files.
18
24
 
@@ -43,7 +49,7 @@ class OmniLogicMockAPI:
43
49
  """
44
50
  paths = filepath.split(",")
45
51
 
46
- self._sim_data: list[dict[str, Any]] = []
52
+ self._sim_data: list[SimData] = []
47
53
  for fp in paths:
48
54
  path = Path(fp)
49
55
  if not path.exists():
@@ -1,8 +1,10 @@
1
1
  from __future__ import annotations
2
2
 
3
- from pydantic import BaseModel, ConfigDict, Field
3
+ from pydantic import BaseModel, ConfigDict, Field, PrivateAttr, ValidationError
4
4
  from xmltodict import parse as xml_parse
5
5
 
6
+ from pyomnilogic_local.models.exceptions import OmniParsingError
7
+
6
8
  # Example Filter Diagnostics XML:
7
9
  #
8
10
  # <?xml version="1.0" encoding="UTF-8" ?>
@@ -46,6 +48,7 @@ class FilterDiagnosticsParameters(BaseModel):
46
48
 
47
49
  class FilterDiagnostics(BaseModel):
48
50
  model_config = ConfigDict(from_attributes=True)
51
+ _raw: str = PrivateAttr(default="")
49
52
 
50
53
  name: str = Field(alias="Name")
51
54
  parameters: list[FilterDiagnosticsParameter] = Field(alias="Parameters")
@@ -64,4 +67,11 @@ class FilterDiagnostics(BaseModel):
64
67
  # The XML nests the Parameter entries under a Parameters entry, this is annoying to work with. Here we are adjusting the data to
65
68
  # remove that extra level in the data
66
69
  data["Response"]["Parameters"] = data["Response"]["Parameters"]["Parameter"]
67
- return FilterDiagnostics.model_validate(data["Response"])
70
+ try:
71
+ instance = FilterDiagnostics.model_validate(data["Response"])
72
+ instance._raw = xml
73
+ except ValidationError as exc:
74
+ msg = f"Failed to parse Filter Diagnostics: {exc}"
75
+ raise OmniParsingError(msg) from exc
76
+ else:
77
+ return instance
@@ -40,4 +40,4 @@ class LeadMessage(BaseModel):
40
40
  if name := param.get("name"):
41
41
  result[name] = int(param.text) if param.text else 0
42
42
  return result
43
- return data
43
+ return data # type: ignore[no-any-return]
@@ -9,6 +9,7 @@ from pydantic import (
9
9
  BaseModel,
10
10
  ConfigDict,
11
11
  Field,
12
+ PrivateAttr,
12
13
  ValidationError,
13
14
  computed_field,
14
15
  model_validator,
@@ -410,6 +411,7 @@ type MSPConfigType = MSPSystem | MSPEquipmentType
410
411
 
411
412
  class MSPConfig(BaseModel):
412
413
  model_config = ConfigDict(from_attributes=True)
414
+ _raw: str = PrivateAttr(default="")
413
415
 
414
416
  system: MSPSystem = Field(alias="System")
415
417
  backyard: MSPBackyard = Field(alias="Backyard")
@@ -459,7 +461,10 @@ class MSPConfig(BaseModel):
459
461
  ),
460
462
  )
461
463
  try:
462
- return MSPConfig.model_validate(data["MSPConfig"], from_attributes=True)
464
+ instance = MSPConfig.model_validate(data["MSPConfig"], from_attributes=True)
465
+ instance._raw = xml
463
466
  except ValidationError as exc:
464
467
  msg = f"Failed to parse MSP Configuration: {exc}"
465
468
  raise OmniParsingError(msg) from exc
469
+ else:
470
+ return instance
@@ -3,7 +3,7 @@ from __future__ import annotations
3
3
 
4
4
  from typing import Any, SupportsInt, cast, overload
5
5
 
6
- from pydantic import BaseModel, ConfigDict, Field, ValidationError, computed_field
6
+ from pydantic import BaseModel, ConfigDict, Field, PrivateAttr, ValidationError, computed_field
7
7
  from xmltodict import parse as xml_parse
8
8
 
9
9
  from pyomnilogic_local.omnitypes import (
@@ -492,6 +492,7 @@ class Telemetry(BaseModel):
492
492
  """
493
493
 
494
494
  model_config = ConfigDict(from_attributes=True)
495
+ _raw: str = PrivateAttr(default="")
495
496
 
496
497
  version: str = Field(alias="@version")
497
498
  backyard: TelemetryBackyard = Field(alias="Backyard")
@@ -525,7 +526,7 @@ class Telemetry(BaseModel):
525
526
 
526
527
  try:
527
528
  newvalue = int(value)
528
- except (ValueError, TypeError):
529
+ except ValueError, TypeError:
529
530
  newvalue = value
530
531
 
531
532
  return key, newvalue
@@ -552,10 +553,13 @@ class Telemetry(BaseModel):
552
553
  ),
553
554
  )
554
555
  try:
555
- return Telemetry.model_validate(data["STATUS"])
556
+ instance = Telemetry.model_validate(data["STATUS"])
557
+ instance._raw = xml
556
558
  except ValidationError as exc:
557
559
  msg = f"Failed to parse Telemetry: {exc}"
558
560
  raise OmniParsingError(msg) from exc
561
+ else:
562
+ return instance
559
563
 
560
564
  def get_telem_by_systemid(self, system_id: int) -> TelemetryType | None:
561
565
  for field_name, value in self:
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "python-omnilogic-local"
3
- version = "0.26.0"
3
+ version = "0.27.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"
@@ -43,14 +43,9 @@ dev = [
43
43
 
44
44
  [tool.mypy]
45
45
  python_version = "3.14"
46
- plugins = [
47
- "pydantic.mypy"
48
- ]
49
- # follow_imports = "silent"
46
+ plugins = ["pydantic.mypy"]
47
+ follow_imports = "normal"
50
48
  strict = true
51
- ignore_missing_imports = true
52
- disallow_subclassing_any = false
53
- warn_return_any = false
54
49
 
55
50
  [tool.ruff]
56
51
  line-length = 140