python-omnilogic-local 0.4.0__tar.gz → 0.4.2__tar.gz

Sign up to get free protection for your applications and to get access to all the features.
Files changed (16) hide show
  1. {python_omnilogic_local-0.4.0 → python_omnilogic_local-0.4.2}/PKG-INFO +1 -1
  2. {python_omnilogic_local-0.4.0 → python_omnilogic_local-0.4.2}/pyomnilogic_local/api.py +47 -13
  3. {python_omnilogic_local-0.4.0 → python_omnilogic_local-0.4.2}/pyomnilogic_local/cli.py +5 -5
  4. {python_omnilogic_local-0.4.0 → python_omnilogic_local-0.4.2}/pyomnilogic_local/models/mspconfig.py +11 -11
  5. {python_omnilogic_local-0.4.0 → python_omnilogic_local-0.4.2}/pyomnilogic_local/models/telemetry.py +14 -14
  6. {python_omnilogic_local-0.4.0 → python_omnilogic_local-0.4.2}/pyproject.toml +1 -1
  7. {python_omnilogic_local-0.4.0 → python_omnilogic_local-0.4.2}/README.md +0 -0
  8. {python_omnilogic_local-0.4.0 → python_omnilogic_local-0.4.2}/pyomnilogic_local/__init__.py +0 -0
  9. {python_omnilogic_local-0.4.0 → python_omnilogic_local-0.4.2}/pyomnilogic_local/models/__init__.py +0 -0
  10. {python_omnilogic_local-0.4.0 → python_omnilogic_local-0.4.2}/pyomnilogic_local/models/const.py +0 -0
  11. {python_omnilogic_local-0.4.0 → python_omnilogic_local-0.4.2}/pyomnilogic_local/models/filter_diagnostics.py +0 -0
  12. {python_omnilogic_local-0.4.0 → python_omnilogic_local-0.4.2}/pyomnilogic_local/models/leadmessage.py +0 -0
  13. {python_omnilogic_local-0.4.0 → python_omnilogic_local-0.4.2}/pyomnilogic_local/models/util.py +0 -0
  14. {python_omnilogic_local-0.4.0 → python_omnilogic_local-0.4.2}/pyomnilogic_local/protocol.py +0 -0
  15. {python_omnilogic_local-0.4.0 → python_omnilogic_local-0.4.2}/pyomnilogic_local/types.py +0 -0
  16. {python_omnilogic_local-0.4.0 → python_omnilogic_local-0.4.2}/pyomnilogic_local/util.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: python-omnilogic-local
3
- Version: 0.4.0
3
+ Version: 0.4.2
4
4
  Summary: A library for local control of Hayward OmniHub/OmniLogic pool controllers using their local API
5
5
  Home-page: https://github.com/cryptk/python-omnilogic-local
6
6
  License: Apache-2.0
@@ -38,6 +38,16 @@ class OmniLogicAPI:
38
38
  ...
39
39
 
40
40
  async def async_send_message(self, message_type: MessageType, message: str | None, need_response: bool = False) -> str | None:
41
+ """Send a message via the Hayward Omni UDP protocol along with properly handling timeouts and responses.
42
+
43
+ Args:
44
+ message_type (MessageType): A selection from MessageType indicating what type of communication you are sending
45
+ message (str | None): The XML body of the message to deliver
46
+ need_response (bool, optional): Should a response be received and returned to the caller. Defaults to False.
47
+
48
+ Returns:
49
+ str | None: The response body sent from the Omni if need_response indicates that a response will be sent
50
+ """
41
51
  loop = asyncio.get_running_loop()
42
52
  transport, protocol = await loop.create_datagram_endpoint(OmniLogicProtocol, remote_addr=(self.controller_ip, self.controller_port))
43
53
 
@@ -53,6 +63,11 @@ class OmniLogicAPI:
53
63
  return resp
54
64
 
55
65
  async def async_get_alarm_list(self) -> str:
66
+ """Retrieve a list of alarms from the Omni.
67
+
68
+ Returns:
69
+ str: An XML body indicating any alarms that are present
70
+ """
56
71
  body_element = ET.Element("Request", {"xmlns": "http://nextgen.hayward.com/api"})
57
72
 
58
73
  name_element = ET.SubElement(body_element, "Name")
@@ -64,6 +79,14 @@ class OmniLogicAPI:
64
79
 
65
80
  @to_pydantic(pydantic_type=MSPConfig)
66
81
  async def async_get_config(self) -> str:
82
+ """Retrieve the MSPConfig from the Omni, optionally parse it into a pydantic model.
83
+
84
+ Args:
85
+ raw (bool): Do not parse the response into a Pydantic model, just return the raw XML. Defaults to False.
86
+
87
+ Returns:
88
+ MSPConfig|str: Either a parsed .models.mspconfig.MSPConfig object or a str depending on arg raw
89
+ """
67
90
  body_element = ET.Element("Request", {"xmlns": "http://nextgen.hayward.com/api"})
68
91
 
69
92
  name_element = ET.SubElement(body_element, "Name")
@@ -75,14 +98,14 @@ class OmniLogicAPI:
75
98
 
76
99
  @to_pydantic(pydantic_type=FilterDiagnostics)
77
100
  async def async_get_filter_diagnostics(self, pool_id: int, equipment_id: int) -> str:
78
- """async_get_filter_diagnostics handles sending a GetUIFilterDiagnosticInfo XML API call to the Hayward Omni pool controller
101
+ """Retrieve filter diagnostics from the Omni, optionally parse it into a pydantic model.
79
102
 
80
103
  Args:
81
104
  pool_id (int): The Pool/BodyOfWater ID that you want to address
82
105
  equipment_id (int): Which equipment_id within that Pool to address
83
106
 
84
107
  Returns:
85
- _type_: _description_
108
+ FilterDiagnostics|str: Either a parsed .models.mspconfig.FilterDiagnostics object or a str depending on arg raw
86
109
  """
87
110
  body_element = ET.Element("Request", {"xmlns": "http://nextgen.hayward.com/api"})
88
111
 
@@ -100,10 +123,20 @@ class OmniLogicAPI:
100
123
  return await self.async_send_message(MessageType.GET_FILTER_DIAGNOSTIC_INFO, req_body, True)
101
124
 
102
125
  async def async_get_log_config(self) -> str:
126
+ """Retrieve the logging configuration from the Omni.
127
+
128
+ Returns:
129
+ str: An XML body describing the logging configuration
130
+ """
103
131
  return await self.async_send_message(MessageType.REQUEST_LOG_CONFIG, None, True)
104
132
 
105
133
  @to_pydantic(pydantic_type=Telemetry)
106
134
  async def async_get_telemetry(self) -> str:
135
+ """Retrieve the current telemetry data from the Omni, optionally parse it into a pydantic model.
136
+
137
+ Returns:
138
+ Telemetry|str: Either a parsed .models.telemetry.Telemetry object or a str depending on arg raw
139
+ """
107
140
  body_element = ET.Element("Request", {"xmlns": "http://nextgen.hayward.com/api"})
108
141
 
109
142
  name_element = ET.SubElement(body_element, "Name")
@@ -114,7 +147,7 @@ class OmniLogicAPI:
114
147
  return await self.async_send_message(MessageType.GET_TELEMETRY, req_body, True)
115
148
 
116
149
  async def async_set_heater(self, pool_id: int, equipment_id: int, temperature: int, unit: str) -> None:
117
- """async_set_heater handles sending a SetUIHeaterCmd XML API call to the Hayward Omni pool controller
150
+ """Set the temperature for a heater on the Omni
118
151
 
119
152
  Args:
120
153
  pool_id (int): The Pool/BodyOfWater ID that you want to address
@@ -123,7 +156,7 @@ class OmniLogicAPI:
123
156
  unit (str): The temperature unit to use (either F or C)
124
157
 
125
158
  Returns:
126
- _type_: _description_
159
+ None
127
160
  """
128
161
  body_element = ET.Element("Request", {"xmlns": "http://nextgen.hayward.com/api"})
129
162
 
@@ -143,7 +176,7 @@ class OmniLogicAPI:
143
176
  return await self.async_send_message(MessageType.SET_HEATER_COMMAND, req_body, False)
144
177
 
145
178
  async def async_set_solar_heater(self, pool_id: int, equipment_id: int, temperature: int, unit: str) -> None:
146
- """async_set_heater handles sending a SetUIHeaterCmd XML API call to the Hayward Omni pool controller
179
+ """Set the solar set point for a heater on the Omni.
147
180
 
148
181
  Args:
149
182
  pool_id (int): The Pool/BodyOfWater ID that you want to address
@@ -152,7 +185,7 @@ class OmniLogicAPI:
152
185
  unit (str): The temperature unit to use (either F or C)
153
186
 
154
187
  Returns:
155
- _type_: _description_
188
+ None
156
189
  """
157
190
  body_element = ET.Element("Request", {"xmlns": "http://nextgen.hayward.com/api"})
158
191
 
@@ -172,15 +205,15 @@ class OmniLogicAPI:
172
205
  return await self.async_send_message(MessageType.SET_SOLAR_SET_POINT_COMMAND, req_body, False)
173
206
 
174
207
  async def async_set_heater_mode(self, pool_id: int, equipment_id: int, mode: HeaterMode) -> None:
175
- """async_set_heater_enable handles sending a SetHeaterEnable XML API call to the Hayward Omni pool controller
208
+ """Set what mode (Heat/Cool/Auto) the heater should use.
176
209
 
177
210
  Args:
178
211
  pool_id (int): The Pool/BodyOfWater ID that you want to address
179
212
  equipment_id (int): Which equipment_id within that Pool to address
180
- enabled (bool, optional): Turn the heater on (True) or off (False)
213
+ mode (HeaterMode): What mode should the heater operate under
181
214
 
182
215
  Returns:
183
- _type_: _description_
216
+ None
184
217
  """
185
218
  body_element = ET.Element("Request", {"xmlns": "http://nextgen.hayward.com/api"})
186
219
 
@@ -240,13 +273,14 @@ class OmniLogicAPI:
240
273
  days_active: int = 0,
241
274
  recurring: bool = False,
242
275
  ) -> None:
243
- """async_set_equipment handles sending a SetUIEquipmentCmd XML API call to the Hayward Omni pool controller
276
+ """Control a piece of equipment, turning it on/off or setting a value (E.g.: filter speed), optionally scheduling it.
244
277
 
245
278
  Args:
246
279
  pool_id (int): The Pool/BodyOfWater ID that you want to address
247
280
  equipment_id (int): Which equipment_id within that Pool to address
248
281
  is_on (Union[int,bool]): For most equipment items, True/False to turn on/off.
249
282
  For Variable Speed Pumps, you can optionally provide an int from 0-100 to set the speed percentage with 0 being Off.
283
+ The interpretation of value depends on the piece of equipment being targeted.
250
284
  is_countdown_timer (bool, optional): For potential future use, included to be "API complete". Defaults to False.
251
285
  startTimeHours (int, optional): For potential future use, included to be "API complete". Defaults to 0.
252
286
  startTimeMinutes (int, optional): For potential future use, included to be "API complete". Defaults to 0.
@@ -265,7 +299,7 @@ class OmniLogicAPI:
265
299
  parameter.text = str(pool_id)
266
300
  parameter = ET.SubElement(parameters_element, "Parameter", name="equipmentId", dataType="int")
267
301
  parameter.text = str(equipment_id)
268
- parameter = ET.SubElement(parameters_element, "Parameter", name="isOn", dataType="int")
302
+ parameter = ET.SubElement(parameters_element, "Parameter", name="isOn", dataType="int", alias="Data")
269
303
  parameter.text = str(int(is_on))
270
304
  parameter = ET.SubElement(parameters_element, "Parameter", name="IsCountDownTimer", dataType="bool")
271
305
  parameter.text = str(int(is_countdown_timer))
@@ -287,7 +321,7 @@ class OmniLogicAPI:
287
321
  return await self.async_send_message(MessageType.SET_EQUIPMENT, req_body, False)
288
322
 
289
323
  async def async_set_filter_speed(self, pool_id: int, equipment_id: int, speed: int) -> None:
290
- """async_set_filter_speed handles sending a SetUIFilterSpeedCmd XML API call to the Hayward Omni pool controller
324
+ """Set the speed for a variable speed filter/pump.
291
325
 
292
326
  Args:
293
327
  pool_id (int): The Pool/BodyOfWater ID that you want to address
@@ -328,7 +362,7 @@ class OmniLogicAPI:
328
362
  days_active: int = 0,
329
363
  recurring: bool = False,
330
364
  ) -> None:
331
- """async_set_light_show handles sending a SetStandAloneLightShow XML API call to the Hayward Omni pool controller
365
+ """Set the desired light show/speed/brightness for a ColorLogic light.
332
366
 
333
367
  Args:
334
368
  pool_id (int): The Pool/BodyOfWater ID that you want to address
@@ -49,14 +49,14 @@ async def async_main() -> None:
49
49
  # b2=chr(diags.get_param_by_name("DisplayFWRevisionB2"))
50
50
  # b3=chr(diags.get_param_by_name("DisplayFWRevisionB3"))
51
51
  # b4=chr(diags.get_param_by_name("DisplayFWRevisionB4"))
52
- # # b5 and b6 are whitespace and a null terminator
53
- # # b5=chr(diags.get_param_by_name("DisplayFWRevisionB5"))
54
- # # b6=chr(diags.get_param_by_name("DisplayFWRevisionB6"))
52
+ # b5 and b6 are whitespace and a null terminator
53
+ # b5=chr(diags.get_param_by_name("DisplayFWRevisionB5"))
54
+ # b6=chr(diags.get_param_by_name("DisplayFWRevisionB6"))
55
55
  # print(f"{b1}{b2}.{b3}.{b4}")
56
- # # Decode the filter power consumption (don't do this, it's returned already decoded in the telemetry)
56
+ # Decode the filter power consumption (don't do this, it's returned already decoded in the telemetry)
57
57
  # p1=diags.get_param_by_name("PowerMSB")
58
58
  # p2=diags.get_param_by_name("PowerLSB")
59
- # # The f-string below converts the bytes to hex and displays them. Just get this value from the telemetry, it's easier
59
+ # The f-string below converts the bytes to hex and displays them. Just get this value from the telemetry, it's easier
60
60
  # print(f"{p1:x}{p2:x}")
61
61
 
62
62
  # Fetch logging configuration
@@ -67,13 +67,13 @@ class MSPSystem(BaseModel):
67
67
 
68
68
  class MSPSensor(OmniBase):
69
69
  omni_type: OmniType = OmniType.SENSOR
70
- type: SensorType = Field(alias="Type")
71
- units: SensorUnits = Field(alias="Units")
70
+ type: SensorType | str = Field(alias="Type")
71
+ units: SensorUnits | str = Field(alias="Units")
72
72
 
73
73
 
74
74
  class MSPFilter(OmniBase):
75
75
  omni_type: OmniType = OmniType.FILTER
76
- type: FilterType = Field(alias="Filter-Type")
76
+ type: FilterType | str = Field(alias="Filter-Type")
77
77
  max_percent: int = Field(alias="Max-Pump-Speed")
78
78
  min_percent: int = Field(alias="Min-Pump-Speed")
79
79
  max_rpm: int = Field(alias="Max-Pump-RPM")
@@ -87,8 +87,8 @@ class MSPFilter(OmniBase):
87
87
 
88
88
  class MSPPump(OmniBase):
89
89
  omni_type: OmniType = OmniType.PUMP
90
- type: PumpType = Field(alias="Type")
91
- function: PumpFunction = Field(alias="Function")
90
+ type: PumpType | str = Field(alias="Type")
91
+ function: PumpFunction | str = Field(alias="Function")
92
92
  max_percent: int = Field(alias="Max-Pump-Speed")
93
93
  min_percent: int = Field(alias="Min-Pump-Speed")
94
94
  max_rpm: int = Field(alias="Max-Pump-RPM")
@@ -102,14 +102,14 @@ class MSPPump(OmniBase):
102
102
 
103
103
  class MSPRelay(OmniBase):
104
104
  omni_type: OmniType = OmniType.RELAY
105
- type: RelayType = Field(alias="Type")
106
- function: RelayFunction = Field(alias="Function")
105
+ type: RelayType | str = Field(alias="Type")
106
+ function: RelayFunction | str = Field(alias="Function")
107
107
 
108
108
 
109
109
  class MSPHeaterEquip(OmniBase):
110
110
  omni_type: OmniType = OmniType.HEATER_EQUIP
111
111
  type: Literal["PET_HEATER"] = Field(alias="Type")
112
- heater_type: HeaterType = Field(alias="Heater-Type")
112
+ heater_type: HeaterType | str = Field(alias="Heater-Type")
113
113
  enabled: Literal["yes", "no"] = Field(alias="Enabled")
114
114
  min_filter_speed: int = Field(alias="Min-Speed-For-Operation")
115
115
  sensor_id: int = Field(alias="Sensor-System-Id")
@@ -139,15 +139,15 @@ class MSPVirtualHeater(OmniBase):
139
139
 
140
140
  class MSPColorLogicLight(OmniBase):
141
141
  omni_type: OmniType = OmniType.CL_LIGHT
142
- type: ColorLogicLightType = Field(alias="Type")
143
- v2_active: Literal["yes", "no"] = Field(alias="V2-Active")
142
+ type: ColorLogicLightType | str = Field(alias="Type")
143
+ v2_active: Literal["yes", "no"] | None = Field(alias="V2-Active")
144
144
 
145
145
 
146
146
  class MSPBoW(OmniBase):
147
147
  _sub_devices = {"filter", "relay", "heater", "sensor", "colorlogic_light"}
148
148
 
149
149
  omni_type: OmniType = OmniType.BOW
150
- type: BodyOfWaterType = Field(alias="Type")
150
+ type: BodyOfWaterType | str = Field(alias="Type")
151
151
  filter: list[MSPFilter] | None = Field(alias="Filter")
152
152
  relay: list[MSPRelay] | None = Field(alias="Relay")
153
153
  heater: MSPVirtualHeater | None = Field(alias="Heater")
@@ -45,7 +45,7 @@ class TelemetryBackyard(BaseModel):
45
45
  system_id: int = Field(alias="@systemId")
46
46
  status_version: int = Field(alias="@statusVersion")
47
47
  air_temp: int = Field(alias="@airTemp")
48
- state: BackyardState = Field(alias="@state")
48
+ state: BackyardState | int = Field(alias="@state")
49
49
  config_checksum: int = Field(alias="@ConfigChksum")
50
50
  msp_version: str = Field(alias="@mspVersion")
51
51
 
@@ -68,27 +68,27 @@ class TelemetryChlorinator(BaseModel):
68
68
  sc_mode: int = Field(alias="@scMode")
69
69
  operating_state: int = Field(alias="@operatingState")
70
70
  timed_percent: int = Field(alias="@Timed-Percent")
71
- operating_mode: ChlorinatorOperatingMode = Field(alias="@operatingMode")
71
+ operating_mode: ChlorinatorOperatingMode | int = Field(alias="@operatingMode")
72
72
  enable: bool = Field(alias="@enable")
73
73
 
74
74
 
75
75
  class TelemetryColorLogicLight(BaseModel):
76
76
  omni_type: OmniType = OmniType.CL_LIGHT
77
77
  system_id: int = Field(alias="@systemId")
78
- state: ColorLogicPowerState = Field(alias="@lightState")
79
- show: ColorLogicShow = Field(alias="@currentShow")
80
- speed: ColorLogicSpeed = Field(alias="@speed")
81
- brightness: ColorLogicBrightness = Field(alias="@brightness")
78
+ state: ColorLogicPowerState | int = Field(alias="@lightState")
79
+ show: ColorLogicShow | int = Field(alias="@currentShow")
80
+ speed: ColorLogicSpeed | int = Field(alias="@speed")
81
+ brightness: ColorLogicBrightness | int = Field(alias="@brightness")
82
82
  special_effect: int = Field(alias="@specialEffect")
83
83
 
84
84
 
85
85
  class TelemetryFilter(BaseModel):
86
86
  omni_type: OmniType = OmniType.FILTER
87
87
  system_id: int = Field(alias="@systemId")
88
- state: FilterState = Field(alias="@filterState")
88
+ state: FilterState | int = Field(alias="@filterState")
89
89
  speed: int = Field(alias="@filterSpeed")
90
- valve_position: FilterValvePosition = Field(alias="@valvePosition")
91
- why_on: FilterWhyOn = Field(alias="@whyFilterIsOn")
90
+ valve_position: FilterValvePosition | int = Field(alias="@valvePosition")
91
+ why_on: FilterWhyOn | int = Field(alias="@whyFilterIsOn")
92
92
  reported_speed: int = Field(alias="@reportedFilterSpeed")
93
93
  power: int = Field(alias="@power")
94
94
  last_speed: int = Field(alias="@lastSpeed")
@@ -103,7 +103,7 @@ class TelemetryGroup(BaseModel):
103
103
  class TelemetryHeater(BaseModel):
104
104
  omni_type: OmniType = OmniType.HEATER
105
105
  system_id: int = Field(alias="@systemId")
106
- state: HeaterState = Field(alias="@heaterState")
106
+ state: HeaterState | int = Field(alias="@heaterState")
107
107
  temp: int = Field(alias="@temp")
108
108
  enabled: bool = Field(alias="@enable")
109
109
  priority: int = Field(alias="@priority")
@@ -113,7 +113,7 @@ class TelemetryHeater(BaseModel):
113
113
  class TelemetryPump(BaseModel):
114
114
  omni_type: OmniType = OmniType.PUMP
115
115
  system_id: int = Field(alias="@systemId")
116
- state: PumpState = Field(alias="@pumpState")
116
+ state: PumpState | int = Field(alias="@pumpState")
117
117
  speed: int = Field(alias="@pummpSpeed")
118
118
  last_speed: int = Field(alias="@lastSpeed")
119
119
  why_on: int = Field(alias="@whyOn")
@@ -122,14 +122,14 @@ class TelemetryPump(BaseModel):
122
122
  class TelemetryRelay(BaseModel):
123
123
  omni_type: OmniType = OmniType.RELAY
124
124
  system_id: int = Field(alias="@systemId")
125
- state: RelayState = Field(alias="@relayState")
125
+ state: RelayState | int = Field(alias="@relayState")
126
126
  why_on: int = Field(alias="@whyOn")
127
127
 
128
128
 
129
129
  class TelemetryValveActuator(BaseModel):
130
130
  omni_type: OmniType = OmniType.VALVE_ACTUATOR
131
131
  system_id: int = Field(alias="@systemId")
132
- state: ValveActuatorState = Field(alias="@valveActuatorState")
132
+ state: ValveActuatorState | int = Field(alias="@valveActuatorState")
133
133
  why_on: int = Field(alias="@whyOn")
134
134
 
135
135
 
@@ -139,7 +139,7 @@ class TelemetryVirtualHeater(BaseModel):
139
139
  current_set_point: int = Field(alias="@Current-Set-Point")
140
140
  enabled: bool = Field(alias="@enable")
141
141
  solar_set_point: int = Field(alias="@SolarSetPoint")
142
- mode: HeaterMode = Field(alias="@Mode")
142
+ mode: HeaterMode | int = Field(alias="@Mode")
143
143
  silent_mode: int = Field(alias="@SilentMode")
144
144
  why_on: int = Field(alias="@whyHeaterIsOn")
145
145
 
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "python-omnilogic-local"
3
- version = "0.4.0"
3
+ version = "0.4.2"
4
4
  description = "A library for local control of Hayward OmniHub/OmniLogic pool controllers using their local API"
5
5
  authors = ["cryptk <cryptk@users.noreply.github.com>", "djtimca", "garionphx"]
6
6
  license = "Apache-2.0"