python-omnilogic-local 0.23.0__tar.gz → 0.25.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.
- {python_omnilogic_local-0.23.0 → python_omnilogic_local-0.25.0}/PKG-INFO +2 -2
- {python_omnilogic_local-0.23.0 → python_omnilogic_local-0.25.0}/pyomnilogic_local/api/api.py +45 -0
- {python_omnilogic_local-0.23.0 → python_omnilogic_local-0.25.0}/pyomnilogic_local/bow.py +1 -1
- {python_omnilogic_local-0.23.0 → python_omnilogic_local-0.25.0}/pyomnilogic_local/cli/get/backyard.py +1 -1
- {python_omnilogic_local-0.23.0 → python_omnilogic_local-0.25.0}/pyomnilogic_local/cli/get/bows.py +1 -1
- {python_omnilogic_local-0.23.0 → python_omnilogic_local-0.25.0}/pyomnilogic_local/cli/get/csads.py +2 -2
- {python_omnilogic_local-0.23.0 → python_omnilogic_local-0.25.0}/pyomnilogic_local/cli/get/filters.py +4 -4
- {python_omnilogic_local-0.23.0 → python_omnilogic_local-0.25.0}/pyomnilogic_local/cli/get/groups.py +1 -1
- {python_omnilogic_local-0.23.0 → python_omnilogic_local-0.25.0}/pyomnilogic_local/cli/get/heaters.py +4 -4
- {python_omnilogic_local-0.23.0 → python_omnilogic_local-0.25.0}/pyomnilogic_local/cli/get/lights.py +4 -4
- {python_omnilogic_local-0.23.0 → python_omnilogic_local-0.25.0}/pyomnilogic_local/cli/get/pumps.py +3 -3
- {python_omnilogic_local-0.23.0 → python_omnilogic_local-0.25.0}/pyomnilogic_local/cli/get/relays.py +4 -4
- {python_omnilogic_local-0.23.0 → python_omnilogic_local-0.25.0}/pyomnilogic_local/cli/get/sensors.py +2 -2
- {python_omnilogic_local-0.23.0 → python_omnilogic_local-0.25.0}/pyomnilogic_local/cli/get/valves.py +4 -4
- {python_omnilogic_local-0.23.0 → python_omnilogic_local-0.25.0}/pyomnilogic_local/csad.py +2 -2
- {python_omnilogic_local-0.23.0 → python_omnilogic_local-0.25.0}/pyomnilogic_local/filter.py +9 -4
- {python_omnilogic_local-0.23.0 → python_omnilogic_local-0.25.0}/pyomnilogic_local/heater.py +5 -2
- {python_omnilogic_local-0.23.0 → python_omnilogic_local-0.25.0}/pyomnilogic_local/heater_equip.py +1 -1
- {python_omnilogic_local-0.23.0 → python_omnilogic_local-0.25.0}/pyomnilogic_local/models/mspconfig.py +1 -3
- {python_omnilogic_local-0.23.0 → python_omnilogic_local-0.25.0}/pyomnilogic_local/omnitypes.py +46 -44
- {python_omnilogic_local-0.23.0 → python_omnilogic_local-0.25.0}/pyomnilogic_local/pump.py +12 -4
- {python_omnilogic_local-0.23.0 → python_omnilogic_local-0.25.0}/pyomnilogic_local/sensor.py +2 -2
- {python_omnilogic_local-0.23.0 → python_omnilogic_local-0.25.0}/pyomnilogic_local/system.py +3 -3
- {python_omnilogic_local-0.23.0 → python_omnilogic_local-0.25.0}/pyomnilogic_local/util.py +9 -3
- {python_omnilogic_local-0.23.0 → python_omnilogic_local-0.25.0}/pyproject.toml +2 -2
- {python_omnilogic_local-0.23.0 → python_omnilogic_local-0.25.0}/LICENSE +0 -0
- {python_omnilogic_local-0.23.0 → python_omnilogic_local-0.25.0}/README.md +0 -0
- {python_omnilogic_local-0.23.0 → python_omnilogic_local-0.25.0}/pyomnilogic_local/__init__.py +0 -0
- {python_omnilogic_local-0.23.0 → python_omnilogic_local-0.25.0}/pyomnilogic_local/_base.py +0 -0
- {python_omnilogic_local-0.23.0 → python_omnilogic_local-0.25.0}/pyomnilogic_local/api/__init__.py +0 -0
- {python_omnilogic_local-0.23.0 → python_omnilogic_local-0.25.0}/pyomnilogic_local/api/constants.py +0 -0
- {python_omnilogic_local-0.23.0 → python_omnilogic_local-0.25.0}/pyomnilogic_local/api/exceptions.py +0 -0
- {python_omnilogic_local-0.23.0 → python_omnilogic_local-0.25.0}/pyomnilogic_local/api/mock_api.py +0 -0
- {python_omnilogic_local-0.23.0 → python_omnilogic_local-0.25.0}/pyomnilogic_local/api/protocol.py +0 -0
- {python_omnilogic_local-0.23.0 → python_omnilogic_local-0.25.0}/pyomnilogic_local/backyard.py +0 -0
- {python_omnilogic_local-0.23.0 → python_omnilogic_local-0.25.0}/pyomnilogic_local/chlorinator.py +0 -0
- {python_omnilogic_local-0.23.0 → python_omnilogic_local-0.25.0}/pyomnilogic_local/chlorinator_equip.py +0 -0
- {python_omnilogic_local-0.23.0 → python_omnilogic_local-0.25.0}/pyomnilogic_local/cli/__init__.py +0 -0
- {python_omnilogic_local-0.23.0 → python_omnilogic_local-0.25.0}/pyomnilogic_local/cli/cli.py +0 -0
- {python_omnilogic_local-0.23.0 → python_omnilogic_local-0.25.0}/pyomnilogic_local/cli/debug/__init__.py +0 -0
- {python_omnilogic_local-0.23.0 → python_omnilogic_local-0.25.0}/pyomnilogic_local/cli/debug/commands.py +0 -0
- {python_omnilogic_local-0.23.0 → python_omnilogic_local-0.25.0}/pyomnilogic_local/cli/get/__init__.py +0 -0
- {python_omnilogic_local-0.23.0 → python_omnilogic_local-0.25.0}/pyomnilogic_local/cli/get/chlorinators.py +0 -0
- {python_omnilogic_local-0.23.0 → python_omnilogic_local-0.25.0}/pyomnilogic_local/cli/get/commands.py +0 -0
- {python_omnilogic_local-0.23.0 → python_omnilogic_local-0.25.0}/pyomnilogic_local/cli/get/schedules.py +0 -0
- {python_omnilogic_local-0.23.0 → python_omnilogic_local-0.25.0}/pyomnilogic_local/cli/pcap_utils.py +0 -0
- {python_omnilogic_local-0.23.0 → python_omnilogic_local-0.25.0}/pyomnilogic_local/cli/utils.py +0 -0
- {python_omnilogic_local-0.23.0 → python_omnilogic_local-0.25.0}/pyomnilogic_local/collections.py +0 -0
- {python_omnilogic_local-0.23.0 → python_omnilogic_local-0.25.0}/pyomnilogic_local/colorlogiclight.py +0 -0
- {python_omnilogic_local-0.23.0 → python_omnilogic_local-0.25.0}/pyomnilogic_local/csad_equip.py +0 -0
- {python_omnilogic_local-0.23.0 → python_omnilogic_local-0.25.0}/pyomnilogic_local/decorators.py +0 -0
- {python_omnilogic_local-0.23.0 → python_omnilogic_local-0.25.0}/pyomnilogic_local/groups.py +0 -0
- {python_omnilogic_local-0.23.0 → python_omnilogic_local-0.25.0}/pyomnilogic_local/models/__init__.py +0 -0
- {python_omnilogic_local-0.23.0 → python_omnilogic_local-0.25.0}/pyomnilogic_local/models/const.py +0 -0
- {python_omnilogic_local-0.23.0 → python_omnilogic_local-0.25.0}/pyomnilogic_local/models/exceptions.py +0 -0
- {python_omnilogic_local-0.23.0 → python_omnilogic_local-0.25.0}/pyomnilogic_local/models/filter_diagnostics.py +0 -0
- {python_omnilogic_local-0.23.0 → python_omnilogic_local-0.25.0}/pyomnilogic_local/models/leadmessage.py +0 -0
- {python_omnilogic_local-0.23.0 → python_omnilogic_local-0.25.0}/pyomnilogic_local/models/telemetry.py +0 -0
- {python_omnilogic_local-0.23.0 → python_omnilogic_local-0.25.0}/pyomnilogic_local/omnilogic.py +0 -0
- {python_omnilogic_local-0.23.0 → python_omnilogic_local-0.25.0}/pyomnilogic_local/py.typed +0 -0
- {python_omnilogic_local-0.23.0 → python_omnilogic_local-0.25.0}/pyomnilogic_local/relay.py +0 -0
- {python_omnilogic_local-0.23.0 → python_omnilogic_local-0.25.0}/pyomnilogic_local/schedule.py +0 -0
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: python-omnilogic-local
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.25.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>
|
|
7
7
|
License-File: LICENSE
|
|
8
8
|
Requires-Dist: pydantic>=2.0.0,<3.0.0
|
|
9
|
-
Requires-Dist: click>=8.0.0,<9.0.0
|
|
10
9
|
Requires-Dist: xmltodict>=1.0.1,<2.0.0
|
|
11
10
|
Requires-Dist: uv~=0.11.6 ; extra == 'build'
|
|
12
11
|
Requires-Dist: scapy>=2.6.1,<3.0.0 ; extra == 'cli'
|
|
12
|
+
Requires-Dist: click>=8.0.0,<9.0.0 ; extra == 'cli'
|
|
13
13
|
Requires-Python: >=3.14.2
|
|
14
14
|
Provides-Extra: build
|
|
15
15
|
Provides-Extra: cli
|
{python_omnilogic_local-0.23.0 → python_omnilogic_local-0.25.0}/pyomnilogic_local/api/api.py
RENAMED
|
@@ -168,8 +168,12 @@ class OmniLogicAPI:
|
|
|
168
168
|
|
|
169
169
|
req_body = ET.tostring(body_element, xml_declaration=True, encoding=XML_ENCODING)
|
|
170
170
|
|
|
171
|
+
_LOGGER.debug("Sending RequestConfiguration with body: %s", req_body)
|
|
172
|
+
|
|
171
173
|
resp = await self.async_send_message(MessageType.REQUEST_CONFIGURATION, req_body, True)
|
|
172
174
|
|
|
175
|
+
_LOGGER.debug("Received response for RequestConfiguration: %s", resp)
|
|
176
|
+
|
|
173
177
|
if raw:
|
|
174
178
|
return resp
|
|
175
179
|
return MSPConfig.load_xml(resp)
|
|
@@ -206,8 +210,12 @@ class OmniLogicAPI:
|
|
|
206
210
|
|
|
207
211
|
req_body = ET.tostring(body_element, xml_declaration=True, encoding=XML_ENCODING)
|
|
208
212
|
|
|
213
|
+
_LOGGER.debug("Sending GetUIFilterDiagnosticInfo with body: %s", req_body)
|
|
214
|
+
|
|
209
215
|
resp = await self.async_send_message(MessageType.GET_FILTER_DIAGNOSTIC_INFO, req_body, True)
|
|
210
216
|
|
|
217
|
+
_LOGGER.debug("Received response for GetUIFilterDiagnosticInfo: %s", resp)
|
|
218
|
+
|
|
211
219
|
if raw:
|
|
212
220
|
return resp
|
|
213
221
|
return FilterDiagnostics.load_xml(resp)
|
|
@@ -231,8 +239,12 @@ class OmniLogicAPI:
|
|
|
231
239
|
|
|
232
240
|
req_body = ET.tostring(body_element, xml_declaration=True, encoding=XML_ENCODING)
|
|
233
241
|
|
|
242
|
+
_LOGGER.debug("Sending RequestTelemetryData with body: %s", req_body)
|
|
243
|
+
|
|
234
244
|
resp = await self.async_send_message(MessageType.GET_TELEMETRY, req_body, True)
|
|
235
245
|
|
|
246
|
+
_LOGGER.debug("Received response for RequestTelemetryData: %s", resp)
|
|
247
|
+
|
|
236
248
|
if raw:
|
|
237
249
|
return resp
|
|
238
250
|
return Telemetry.load_xml(resp)
|
|
@@ -268,6 +280,8 @@ class OmniLogicAPI:
|
|
|
268
280
|
|
|
269
281
|
req_body = ET.tostring(body_element, xml_declaration=True, encoding=XML_ENCODING)
|
|
270
282
|
|
|
283
|
+
_LOGGER.debug("Sending SetUIHeaterCmd with body: %s", req_body)
|
|
284
|
+
|
|
271
285
|
return await self.async_send_message(MessageType.SET_HEATER_COMMAND, req_body, False)
|
|
272
286
|
|
|
273
287
|
async def async_set_solar_heater(
|
|
@@ -301,6 +315,8 @@ class OmniLogicAPI:
|
|
|
301
315
|
|
|
302
316
|
req_body = ET.tostring(body_element, xml_declaration=True, encoding=XML_ENCODING)
|
|
303
317
|
|
|
318
|
+
_LOGGER.debug("Sending SetUISolarSetPointCmd with body: %s", req_body)
|
|
319
|
+
|
|
304
320
|
return await self.async_send_message(MessageType.SET_SOLAR_SET_POINT_COMMAND, req_body, False)
|
|
305
321
|
|
|
306
322
|
async def async_set_heater_mode(
|
|
@@ -334,6 +350,8 @@ class OmniLogicAPI:
|
|
|
334
350
|
|
|
335
351
|
req_body = ET.tostring(body_element, xml_declaration=True, encoding=XML_ENCODING)
|
|
336
352
|
|
|
353
|
+
_LOGGER.debug("Sending SetUIHeaterModeCmd with body: %s", req_body)
|
|
354
|
+
|
|
337
355
|
return await self.async_send_message(MessageType.SET_HEATER_MODE_COMMAND, req_body, False)
|
|
338
356
|
|
|
339
357
|
async def async_set_heater_enable(
|
|
@@ -367,6 +385,8 @@ class OmniLogicAPI:
|
|
|
367
385
|
|
|
368
386
|
req_body = ET.tostring(body_element, xml_declaration=True, encoding=XML_ENCODING)
|
|
369
387
|
|
|
388
|
+
_LOGGER.debug("Sending SetHeaterEnable with body: %s", req_body)
|
|
389
|
+
|
|
370
390
|
return await self.async_send_message(MessageType.SET_HEATER_ENABLED, req_body, False)
|
|
371
391
|
|
|
372
392
|
async def async_set_equipment(
|
|
@@ -427,6 +447,8 @@ class OmniLogicAPI:
|
|
|
427
447
|
|
|
428
448
|
req_body = ET.tostring(body_element, xml_declaration=True, encoding=XML_ENCODING)
|
|
429
449
|
|
|
450
|
+
_LOGGER.debug("Sending SetUIEquipmentCmd with body: %s", req_body)
|
|
451
|
+
|
|
430
452
|
return await self.async_send_message(MessageType.SET_EQUIPMENT, req_body, False)
|
|
431
453
|
|
|
432
454
|
async def async_set_filter_speed(self, pool_id: int, equipment_id: int, speed: int) -> None:
|
|
@@ -453,6 +475,8 @@ class OmniLogicAPI:
|
|
|
453
475
|
|
|
454
476
|
req_body = ET.tostring(body_element, xml_declaration=True, encoding=XML_ENCODING)
|
|
455
477
|
|
|
478
|
+
_LOGGER.debug("Sending SetUIFilterSpeedCmd with body: %s", req_body)
|
|
479
|
+
|
|
456
480
|
return await self.async_send_message(MessageType.SET_FILTER_SPEED, req_body, False)
|
|
457
481
|
|
|
458
482
|
async def async_set_light_show(
|
|
@@ -522,6 +546,9 @@ class OmniLogicAPI:
|
|
|
522
546
|
parameter.text = str(int(recurring))
|
|
523
547
|
|
|
524
548
|
req_body = ET.tostring(body_element, xml_declaration=True, encoding=XML_ENCODING)
|
|
549
|
+
|
|
550
|
+
_LOGGER.debug("Sending SetStandAloneLightShow with body: %s", req_body)
|
|
551
|
+
|
|
525
552
|
return await self.async_send_message(MessageType.SET_STANDALONE_LIGHT_SHOW, req_body, False)
|
|
526
553
|
|
|
527
554
|
async def async_set_chlorinator_enable(self, pool_id: int, enabled: int | bool) -> None:
|
|
@@ -538,6 +565,8 @@ class OmniLogicAPI:
|
|
|
538
565
|
|
|
539
566
|
req_body = ET.tostring(body_element, xml_declaration=True, encoding=XML_ENCODING)
|
|
540
567
|
|
|
568
|
+
_LOGGER.debug("Sending SetCHLOREnable with body: %s", req_body)
|
|
569
|
+
|
|
541
570
|
return await self.async_send_message(MessageType.SET_CHLOR_ENABLED, req_body, False)
|
|
542
571
|
|
|
543
572
|
# This is used to set the ORP target value on a CSAD
|
|
@@ -562,6 +591,8 @@ class OmniLogicAPI:
|
|
|
562
591
|
|
|
563
592
|
req_body = ET.tostring(body_element, xml_declaration=True, encoding=XML_ENCODING)
|
|
564
593
|
|
|
594
|
+
_LOGGER.debug("Sending SetUICSADORPTargetLevel with body: %s", req_body)
|
|
595
|
+
|
|
565
596
|
return await self.async_send_message(MessageType.SET_CSAD_ORP_TARGET, req_body, False)
|
|
566
597
|
|
|
567
598
|
# This is used to set the pH target value on a CSAD
|
|
@@ -586,6 +617,8 @@ class OmniLogicAPI:
|
|
|
586
617
|
|
|
587
618
|
req_body = ET.tostring(body_element, xml_declaration=True, encoding=XML_ENCODING)
|
|
588
619
|
|
|
620
|
+
_LOGGER.debug("Sending UISetCSADTargetValue with body: %s", req_body)
|
|
621
|
+
|
|
589
622
|
return await self.async_send_message(MessageType.SET_CSAD_TARGET_VALUE, req_body, False)
|
|
590
623
|
|
|
591
624
|
async def async_set_chlorinator_params(
|
|
@@ -627,6 +660,8 @@ class OmniLogicAPI:
|
|
|
627
660
|
|
|
628
661
|
req_body = ET.tostring(body_element, xml_declaration=True, encoding=XML_ENCODING)
|
|
629
662
|
|
|
663
|
+
_LOGGER.debug("Sending SetCHLORParams with body: %s", req_body)
|
|
664
|
+
|
|
630
665
|
return await self.async_send_message(MessageType.SET_CHLOR_PARAMS, req_body, False)
|
|
631
666
|
|
|
632
667
|
async def async_set_chlorinator_superchlorinate(
|
|
@@ -650,6 +685,8 @@ class OmniLogicAPI:
|
|
|
650
685
|
|
|
651
686
|
req_body = ET.tostring(body_element, xml_declaration=True, encoding=XML_ENCODING)
|
|
652
687
|
|
|
688
|
+
_LOGGER.debug("Sending SetUISuperCHLORCmd with body: %s", req_body)
|
|
689
|
+
|
|
653
690
|
return await self.async_send_message(MessageType.SET_SUPERCHLORINATE, req_body, False)
|
|
654
691
|
|
|
655
692
|
async def async_restore_idle_state(self) -> None:
|
|
@@ -662,6 +699,8 @@ class OmniLogicAPI:
|
|
|
662
699
|
|
|
663
700
|
req_body = ET.tostring(body_element, xml_declaration=True, encoding=XML_ENCODING)
|
|
664
701
|
|
|
702
|
+
_LOGGER.debug("Sending RestoreIdleState with body: %s", req_body)
|
|
703
|
+
|
|
665
704
|
return await self.async_send_message(MessageType.RESTORE_IDLE_STATE, req_body, False)
|
|
666
705
|
|
|
667
706
|
async def async_set_spillover(
|
|
@@ -703,6 +742,8 @@ class OmniLogicAPI:
|
|
|
703
742
|
|
|
704
743
|
req_body = ET.tostring(body_element, xml_declaration=True, encoding=XML_ENCODING)
|
|
705
744
|
|
|
745
|
+
_LOGGER.debug("Sending SetUISpilloverCmd with body: %s", req_body)
|
|
746
|
+
|
|
706
747
|
return await self.async_send_message(MessageType.SET_SPILLOVER, req_body, False)
|
|
707
748
|
|
|
708
749
|
async def async_set_group_enable(
|
|
@@ -744,6 +785,8 @@ class OmniLogicAPI:
|
|
|
744
785
|
|
|
745
786
|
req_body = ET.tostring(body_element, xml_declaration=True, encoding=XML_ENCODING)
|
|
746
787
|
|
|
788
|
+
_LOGGER.debug("Sending RunGroupCmd with body: %s", req_body)
|
|
789
|
+
|
|
747
790
|
return await self.async_send_message(MessageType.RUN_GROUP_CMD, req_body, False)
|
|
748
791
|
|
|
749
792
|
async def async_edit_schedule(
|
|
@@ -815,4 +858,6 @@ class OmniLogicAPI:
|
|
|
815
858
|
|
|
816
859
|
req_body = ET.tostring(body_element, xml_declaration=True, encoding=XML_ENCODING)
|
|
817
860
|
|
|
861
|
+
_LOGGER.debug("Sending EditUIScheduleCmd with body: %s", req_body)
|
|
862
|
+
|
|
818
863
|
return await self.async_send_message(MessageType.EDIT_SCHEDULE, req_body, False)
|
|
@@ -170,7 +170,7 @@ class Bow(OmniEquipment[MSPBoW, TelemetryBoW]):
|
|
|
170
170
|
return f"Bow({', '.join(parts)})"
|
|
171
171
|
|
|
172
172
|
@property
|
|
173
|
-
def equip_type(self) -> BodyOfWaterType
|
|
173
|
+
def equip_type(self) -> BodyOfWaterType:
|
|
174
174
|
"""The equipment type of the bow (POOL or SPA)."""
|
|
175
175
|
return self.mspconfig.equip_type
|
|
176
176
|
|
|
@@ -54,7 +54,7 @@ def _print_backyard_info(backyardconfig: MSPBackyard, telemetry: TelemetryType |
|
|
|
54
54
|
continue
|
|
55
55
|
|
|
56
56
|
if attr_name == "state":
|
|
57
|
-
value = BackyardState(value)
|
|
57
|
+
value = str(BackyardState(value))
|
|
58
58
|
elif isinstance(value, list):
|
|
59
59
|
# Format lists nicely
|
|
60
60
|
value = ", ".join(str(v) for v in value) if value else "None"
|
{python_omnilogic_local-0.23.0 → python_omnilogic_local-0.25.0}/pyomnilogic_local/cli/get/bows.py
RENAMED
|
@@ -58,7 +58,7 @@ def _print_bow_info(bow: MSPBoW, telemetry: TelemetryType | None) -> None:
|
|
|
58
58
|
continue
|
|
59
59
|
|
|
60
60
|
if attr_name == "type":
|
|
61
|
-
value = BodyOfWaterType(value)
|
|
61
|
+
value = str(BodyOfWaterType(value))
|
|
62
62
|
elif isinstance(value, list):
|
|
63
63
|
# Format lists nicely
|
|
64
64
|
value = ", ".join(str(v) for v in value) if value else "None"
|
{python_omnilogic_local-0.23.0 → python_omnilogic_local-0.25.0}/pyomnilogic_local/cli/get/csads.py
RENAMED
|
@@ -50,9 +50,9 @@ def _print_csad_info(csad: MSPCSAD, telemetry: TelemetryCSAD | None) -> None:
|
|
|
50
50
|
csad_data: dict[Any, Any] = {**dict(csad), **dict(telemetry)} if telemetry else dict(csad)
|
|
51
51
|
for attr_name, value in csad_data.items():
|
|
52
52
|
if attr_name == "equip_type":
|
|
53
|
-
value = CSADType(value)
|
|
53
|
+
value = str(CSADType(value))
|
|
54
54
|
elif attr_name == "mode":
|
|
55
|
-
value = CSADMode(value)
|
|
55
|
+
value = str(CSADMode(value))
|
|
56
56
|
elif isinstance(value, list):
|
|
57
57
|
# Format lists nicely
|
|
58
58
|
value = ", ".join(str(v) for v in value) if value else "None"
|
{python_omnilogic_local-0.23.0 → python_omnilogic_local-0.25.0}/pyomnilogic_local/cli/get/filters.py
RENAMED
|
@@ -50,13 +50,13 @@ def _print_filter_info(filt: MSPFilter, telemetry: TelemetryType | None) -> None
|
|
|
50
50
|
filter_data: dict[Any, Any] = {**dict(filt), **dict(telemetry)} if telemetry else dict(filt)
|
|
51
51
|
for attr_name, value in filter_data.items():
|
|
52
52
|
if attr_name == "state":
|
|
53
|
-
value = FilterState(value)
|
|
53
|
+
value = str(FilterState(value))
|
|
54
54
|
elif attr_name == "type":
|
|
55
|
-
value = FilterType(value)
|
|
55
|
+
value = str(FilterType(value))
|
|
56
56
|
elif attr_name == "valve_position":
|
|
57
|
-
value = FilterValvePosition(value)
|
|
57
|
+
value = str(FilterValvePosition(value))
|
|
58
58
|
elif attr_name == "why_on":
|
|
59
|
-
value = FilterWhyOn(value)
|
|
59
|
+
value = str(FilterWhyOn(value))
|
|
60
60
|
elif isinstance(value, list):
|
|
61
61
|
# Format lists nicely
|
|
62
62
|
value = ", ".join(str(v) for v in value) if value else "None"
|
{python_omnilogic_local-0.23.0 → python_omnilogic_local-0.25.0}/pyomnilogic_local/cli/get/groups.py
RENAMED
|
@@ -53,7 +53,7 @@ def _print_group_info(group: MSPGroup, telemetry: TelemetryGroup | None) -> None
|
|
|
53
53
|
# Skip bow_id as it's not relevant for groups
|
|
54
54
|
continue
|
|
55
55
|
if attr_name == "state":
|
|
56
|
-
value = GroupState(value)
|
|
56
|
+
value = str(GroupState(value))
|
|
57
57
|
elif isinstance(value, list):
|
|
58
58
|
# Format lists nicely
|
|
59
59
|
value = ", ".join(str(v) for v in value) if value else "None"
|
{python_omnilogic_local-0.23.0 → python_omnilogic_local-0.25.0}/pyomnilogic_local/cli/get/heaters.py
RENAMED
|
@@ -67,9 +67,9 @@ def _print_virtual_heater_info(virt_heater: MSPVirtualHeater, telemetry: Telemet
|
|
|
67
67
|
|
|
68
68
|
for attr_name, value in display_data.items():
|
|
69
69
|
if attr_name == "state":
|
|
70
|
-
value = HeaterState(value)
|
|
70
|
+
value = str(HeaterState(value))
|
|
71
71
|
elif attr_name == "mode":
|
|
72
|
-
value = HeaterMode(value)
|
|
72
|
+
value = str(HeaterMode(value))
|
|
73
73
|
elif isinstance(value, list):
|
|
74
74
|
# Format lists nicely
|
|
75
75
|
value = ", ".join(str(v) for v in value) if value else "None"
|
|
@@ -105,9 +105,9 @@ def _print_heater_equipment_info(equip: MSPHeaterEquip, telemetry: Telemetry) ->
|
|
|
105
105
|
|
|
106
106
|
for attr_name, value in equip_data.items():
|
|
107
107
|
if attr_name == "heater_type":
|
|
108
|
-
value = HeaterType(value)
|
|
108
|
+
value = str(HeaterType(value))
|
|
109
109
|
elif attr_name == "state":
|
|
110
|
-
value = HeaterState(value)
|
|
110
|
+
value = str(HeaterState(value))
|
|
111
111
|
elif isinstance(value, list):
|
|
112
112
|
value = ", ".join(str(v) for v in value) if value else "None"
|
|
113
113
|
|
{python_omnilogic_local-0.23.0 → python_omnilogic_local-0.25.0}/pyomnilogic_local/cli/get/lights.py
RENAMED
|
@@ -51,16 +51,16 @@ def _print_light_info(light: MSPColorLogicLight, telemetry: TelemetryColorLogicL
|
|
|
51
51
|
|
|
52
52
|
for attr_name, value in light_data.items():
|
|
53
53
|
if attr_name == "brightness":
|
|
54
|
-
value = ColorLogicBrightness(value)
|
|
54
|
+
value = str(ColorLogicBrightness(value))
|
|
55
55
|
elif attr_name == "effects" and isinstance(value, list):
|
|
56
|
-
show_names = [
|
|
56
|
+
show_names = [str(show) for show in value]
|
|
57
57
|
value = ", ".join(show_names) if show_names else "None"
|
|
58
58
|
elif attr_name == "show" and value is not None:
|
|
59
59
|
value = telemetry.show_name(light.equip_type, light.v2_active) if telemetry else str(value)
|
|
60
60
|
elif attr_name == "speed":
|
|
61
|
-
value = ColorLogicSpeed(value)
|
|
61
|
+
value = str(ColorLogicSpeed(value))
|
|
62
62
|
elif attr_name == "state":
|
|
63
|
-
value = ColorLogicPowerState(value)
|
|
63
|
+
value = str(ColorLogicPowerState(value))
|
|
64
64
|
elif isinstance(value, list):
|
|
65
65
|
# Format other lists nicely
|
|
66
66
|
value = ", ".join(str(v) for v in value) if value else "None"
|
{python_omnilogic_local-0.23.0 → python_omnilogic_local-0.25.0}/pyomnilogic_local/cli/get/pumps.py
RENAMED
|
@@ -50,11 +50,11 @@ def _print_pump_info(pump: MSPPump, telemetry: TelemetryType | None) -> None:
|
|
|
50
50
|
pump_data: dict[Any, Any] = {**dict(pump), **dict(telemetry)} if telemetry else dict(pump)
|
|
51
51
|
for attr_name, value in pump_data.items():
|
|
52
52
|
if attr_name == "state":
|
|
53
|
-
value = PumpState(value)
|
|
53
|
+
value = str(PumpState(value))
|
|
54
54
|
elif attr_name == "equip_type":
|
|
55
|
-
value = PumpType(value)
|
|
55
|
+
value = str(PumpType(value))
|
|
56
56
|
elif attr_name == "function":
|
|
57
|
-
value = PumpFunction(value)
|
|
57
|
+
value = str(PumpFunction(value))
|
|
58
58
|
elif isinstance(value, list):
|
|
59
59
|
# Format lists nicely
|
|
60
60
|
value = ", ".join(str(v) for v in value) if value else "None"
|
{python_omnilogic_local-0.23.0 → python_omnilogic_local-0.25.0}/pyomnilogic_local/cli/get/relays.py
RENAMED
|
@@ -50,13 +50,13 @@ def _print_relay_info(relay: MSPRelay, telemetry: TelemetryType | None) -> None:
|
|
|
50
50
|
relay_data: dict[Any, Any] = {**dict(relay), **dict(telemetry)} if telemetry else dict(relay)
|
|
51
51
|
for attr_name, value in relay_data.items():
|
|
52
52
|
if attr_name == "state":
|
|
53
|
-
value = RelayState(value)
|
|
53
|
+
value = str(RelayState(value))
|
|
54
54
|
elif attr_name == "type":
|
|
55
|
-
value = RelayType(value)
|
|
55
|
+
value = str(RelayType(value))
|
|
56
56
|
elif attr_name == "function":
|
|
57
|
-
value = RelayFunction(value)
|
|
57
|
+
value = str(RelayFunction(value))
|
|
58
58
|
elif attr_name == "why_on":
|
|
59
|
-
value = RelayWhyOn(value)
|
|
59
|
+
value = str(RelayWhyOn(value))
|
|
60
60
|
elif isinstance(value, list):
|
|
61
61
|
# Format lists nicely
|
|
62
62
|
value = ", ".join(str(v) for v in value) if value else "None"
|
{python_omnilogic_local-0.23.0 → python_omnilogic_local-0.25.0}/pyomnilogic_local/cli/get/sensors.py
RENAMED
|
@@ -48,9 +48,9 @@ def _print_sensor_info(sensor: MSPSensor) -> None:
|
|
|
48
48
|
sensor_data: dict[Any, Any] = dict(sensor)
|
|
49
49
|
for attr_name, value in sensor_data.items():
|
|
50
50
|
if attr_name == "equip_type":
|
|
51
|
-
value = SensorType(value)
|
|
51
|
+
value = str(SensorType(value))
|
|
52
52
|
elif attr_name == "units":
|
|
53
|
-
value = SensorUnits(value)
|
|
53
|
+
value = str(SensorUnits(value))
|
|
54
54
|
elif isinstance(value, list):
|
|
55
55
|
# Format lists nicely
|
|
56
56
|
value = ", ".join(str(v) for v in value) if value else "None"
|
{python_omnilogic_local-0.23.0 → python_omnilogic_local-0.25.0}/pyomnilogic_local/cli/get/valves.py
RENAMED
|
@@ -60,13 +60,13 @@ def _print_valve_info(relay: MSPRelay, telemetry: Telemetry) -> None:
|
|
|
60
60
|
|
|
61
61
|
for attr_name, value in valve_data.items():
|
|
62
62
|
if attr_name == "type":
|
|
63
|
-
value = RelayType(value)
|
|
63
|
+
value = str(RelayType(value))
|
|
64
64
|
elif attr_name == "function":
|
|
65
|
-
value = RelayFunction(value)
|
|
65
|
+
value = str(RelayFunction(value))
|
|
66
66
|
elif attr_name == "state":
|
|
67
|
-
value = ValveActuatorState(value)
|
|
67
|
+
value = str(ValveActuatorState(value))
|
|
68
68
|
elif attr_name == "why_on":
|
|
69
|
-
value = RelayWhyOn(value)
|
|
69
|
+
value = str(RelayWhyOn(value))
|
|
70
70
|
elif isinstance(value, list):
|
|
71
71
|
# Format lists nicely
|
|
72
72
|
value = ", ".join(str(v) for v in value) if value else "None"
|
|
@@ -69,7 +69,7 @@ class CSAD(OmniEquipment[MSPCSAD, TelemetryCSAD]):
|
|
|
69
69
|
return self.mspconfig.enabled
|
|
70
70
|
|
|
71
71
|
@property
|
|
72
|
-
def equip_type(self) -> CSADType
|
|
72
|
+
def equip_type(self) -> CSADType:
|
|
73
73
|
"""Type of CSAD system (ACID or CO2)."""
|
|
74
74
|
return self.mspconfig.equip_type
|
|
75
75
|
|
|
@@ -160,7 +160,7 @@ class CSAD(OmniEquipment[MSPCSAD, TelemetryCSAD]):
|
|
|
160
160
|
return self.telemetry.orp
|
|
161
161
|
|
|
162
162
|
@property
|
|
163
|
-
def mode(self) -> CSADMode
|
|
163
|
+
def mode(self) -> CSADMode:
|
|
164
164
|
"""Current operating mode of the CSAD.
|
|
165
165
|
|
|
166
166
|
Returns:
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
from typing import TYPE_CHECKING
|
|
4
|
+
|
|
3
5
|
from pyomnilogic_local._base import OmniEquipment
|
|
4
6
|
from pyomnilogic_local.decorators import control_method
|
|
5
7
|
from pyomnilogic_local.models.mspconfig import MSPFilter
|
|
@@ -7,6 +9,9 @@ from pyomnilogic_local.models.telemetry import TelemetryFilter
|
|
|
7
9
|
from pyomnilogic_local.omnitypes import FilterSpeedPresets, FilterState
|
|
8
10
|
from pyomnilogic_local.util import OmniEquipmentNotInitializedError
|
|
9
11
|
|
|
12
|
+
if TYPE_CHECKING:
|
|
13
|
+
from pyomnilogic_local.omnitypes import FilterType, FilterValvePosition, FilterWhyOn
|
|
14
|
+
|
|
10
15
|
|
|
11
16
|
class Filter(OmniEquipment[MSPFilter, TelemetryFilter]):
|
|
12
17
|
"""Represents a pool/spa filtration pump in the OmniLogic system.
|
|
@@ -81,7 +86,7 @@ class Filter(OmniEquipment[MSPFilter, TelemetryFilter]):
|
|
|
81
86
|
|
|
82
87
|
# Expose MSPConfig attributes
|
|
83
88
|
@property
|
|
84
|
-
def equip_type(self) ->
|
|
89
|
+
def equip_type(self) -> FilterType:
|
|
85
90
|
"""The filter type (e.g., FMT_VARIABLE_SPEED_PUMP)."""
|
|
86
91
|
return self.mspconfig.equip_type
|
|
87
92
|
|
|
@@ -127,7 +132,7 @@ class Filter(OmniEquipment[MSPFilter, TelemetryFilter]):
|
|
|
127
132
|
|
|
128
133
|
# Expose Telemetry attributes
|
|
129
134
|
@property
|
|
130
|
-
def state(self) -> FilterState
|
|
135
|
+
def state(self) -> FilterState:
|
|
131
136
|
"""Current filter state."""
|
|
132
137
|
return self.telemetry.state
|
|
133
138
|
|
|
@@ -137,12 +142,12 @@ class Filter(OmniEquipment[MSPFilter, TelemetryFilter]):
|
|
|
137
142
|
return self.telemetry.speed
|
|
138
143
|
|
|
139
144
|
@property
|
|
140
|
-
def valve_position(self) ->
|
|
145
|
+
def valve_position(self) -> FilterValvePosition:
|
|
141
146
|
"""Current valve position."""
|
|
142
147
|
return self.telemetry.valve_position
|
|
143
148
|
|
|
144
149
|
@property
|
|
145
|
-
def why_on(self) ->
|
|
150
|
+
def why_on(self) -> FilterWhyOn:
|
|
146
151
|
"""Reason why the filter is on."""
|
|
147
152
|
return self.telemetry.why_on
|
|
148
153
|
|
|
@@ -140,7 +140,7 @@ class Heater(OmniEquipment[MSPVirtualHeater, TelemetryVirtualHeater]):
|
|
|
140
140
|
return self.mspconfig.min_temp
|
|
141
141
|
|
|
142
142
|
@property
|
|
143
|
-
def mode(self) -> HeaterMode
|
|
143
|
+
def mode(self) -> HeaterMode:
|
|
144
144
|
"""Returns the current heater mode from telemetry."""
|
|
145
145
|
return self.telemetry.mode
|
|
146
146
|
|
|
@@ -174,7 +174,10 @@ class Heater(OmniEquipment[MSPVirtualHeater, TelemetryVirtualHeater]):
|
|
|
174
174
|
|
|
175
175
|
@property
|
|
176
176
|
def why_on(self) -> int:
|
|
177
|
-
"""Returns the reason why the heater is on from telemetry.
|
|
177
|
+
"""Returns the reason why the heater is on from telemetry.
|
|
178
|
+
|
|
179
|
+
We don't have a good understanding of what these values mean yet
|
|
180
|
+
"""
|
|
178
181
|
return self.telemetry.why_on
|
|
179
182
|
|
|
180
183
|
@property
|
{python_omnilogic_local-0.23.0 → python_omnilogic_local-0.25.0}/pyomnilogic_local/heater_equip.py
RENAMED
|
@@ -110,7 +110,7 @@ class HeaterEquipment(OmniEquipment[MSPHeaterEquip, TelemetryHeater]):
|
|
|
110
110
|
return self.mspconfig.supports_cooling
|
|
111
111
|
|
|
112
112
|
@property
|
|
113
|
-
def state(self) -> HeaterState
|
|
113
|
+
def state(self) -> HeaterState:
|
|
114
114
|
"""Returns the current state of the heater equipment (OFF, ON, or PAUSE)."""
|
|
115
115
|
return self.telemetry.state
|
|
116
116
|
|
|
@@ -59,9 +59,7 @@ class OmniBase(BaseModel):
|
|
|
59
59
|
|
|
60
60
|
def without_subdevices(self) -> Self:
|
|
61
61
|
data = self.model_dump(exclude=self._sub_devices, round_trip=True, by_alias=True)
|
|
62
|
-
|
|
63
|
-
_LOGGER.debug("without_subdevices: original=%s, copied=%s", self, copied)
|
|
64
|
-
return copied
|
|
62
|
+
return self.model_validate(data)
|
|
65
63
|
|
|
66
64
|
def propagate_bow_id(self, bow_id: int) -> None:
|
|
67
65
|
# First we set our own bow_id
|
{python_omnilogic_local-0.23.0 → python_omnilogic_local-0.25.0}/pyomnilogic_local/omnitypes.py
RENAMED
|
@@ -6,7 +6,7 @@ from .util import PrettyEnum
|
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
# OmniAPI Enums
|
|
9
|
-
class MessageType(
|
|
9
|
+
class MessageType(PrettyEnum, IntEnum):
|
|
10
10
|
XML_ACK = 0000
|
|
11
11
|
REQUEST_CONFIGURATION = 1
|
|
12
12
|
SET_FILTER_SPEED = 9
|
|
@@ -39,7 +39,7 @@ class MessageType(IntEnum, PrettyEnum):
|
|
|
39
39
|
MSP_BLOCKMESSAGE = 1999
|
|
40
40
|
|
|
41
41
|
|
|
42
|
-
class ClientType(
|
|
42
|
+
class ClientType(PrettyEnum, IntEnum):
|
|
43
43
|
XML = 0
|
|
44
44
|
SIMPLE = 1
|
|
45
45
|
OMNI = 3
|
|
@@ -71,7 +71,7 @@ class OmniType(StrEnum):
|
|
|
71
71
|
|
|
72
72
|
|
|
73
73
|
# Backyard/BoW
|
|
74
|
-
class BackyardState(
|
|
74
|
+
class BackyardState(PrettyEnum, IntEnum):
|
|
75
75
|
OFF = 0
|
|
76
76
|
ON = 1
|
|
77
77
|
SERVICE_MODE = 2
|
|
@@ -79,12 +79,12 @@ class BackyardState(IntEnum, PrettyEnum):
|
|
|
79
79
|
TIMED_SERVICE_MODE = 4
|
|
80
80
|
|
|
81
81
|
|
|
82
|
-
class BodyOfWaterState(
|
|
82
|
+
class BodyOfWaterState(PrettyEnum, IntEnum):
|
|
83
83
|
NO_FLOW = 0
|
|
84
84
|
FLOW = 1
|
|
85
85
|
|
|
86
86
|
|
|
87
|
-
class BodyOfWaterType(
|
|
87
|
+
class BodyOfWaterType(PrettyEnum, StrEnum):
|
|
88
88
|
POOL = "BOW_POOL"
|
|
89
89
|
SPA = "BOW_SPA"
|
|
90
90
|
|
|
@@ -150,26 +150,26 @@ class ChlorinatorError(Flag):
|
|
|
150
150
|
AQUARITE_PCB_ERROR = 1 << 14
|
|
151
151
|
|
|
152
152
|
|
|
153
|
-
class ChlorinatorOperatingMode(
|
|
153
|
+
class ChlorinatorOperatingMode(PrettyEnum, IntEnum):
|
|
154
154
|
DISABLED = 0
|
|
155
155
|
TIMED = 1
|
|
156
156
|
ORP_AUTO = 2
|
|
157
157
|
ORP_TIMED_RW = 3 # Chlorinator in ORP mode experienced CSAD condition that prevents ORP operation
|
|
158
158
|
|
|
159
159
|
|
|
160
|
-
class ChlorinatorType(
|
|
160
|
+
class ChlorinatorType(PrettyEnum, StrEnum):
|
|
161
161
|
MAIN_PANEL = "CHLOR_TYPE_MAIN_PANEL"
|
|
162
162
|
DISPENSER = "CHLOR_TYPE_DISPENSER"
|
|
163
163
|
AQUA_RITE = "CHLOR_TYPE_AQUA_RITE"
|
|
164
164
|
|
|
165
165
|
|
|
166
|
-
class ChlorinatorDispenserType(
|
|
166
|
+
class ChlorinatorDispenserType(PrettyEnum, StrEnum):
|
|
167
167
|
SALT = "SALT_DISPENSING"
|
|
168
168
|
LIQUID = "LIQUID_DISPENSING"
|
|
169
169
|
TABLET = "TABLET_DISPENSING"
|
|
170
170
|
|
|
171
171
|
|
|
172
|
-
class ChlorinatorCellType(
|
|
172
|
+
class ChlorinatorCellType(PrettyEnum, IntEnum):
|
|
173
173
|
CELL_TYPE_UNKNOWN = 0
|
|
174
174
|
CELL_TYPE_T3 = 1
|
|
175
175
|
CELL_TYPE_T5 = 2
|
|
@@ -184,7 +184,7 @@ class ChlorinatorCellType(IntEnum, PrettyEnum):
|
|
|
184
184
|
|
|
185
185
|
|
|
186
186
|
# Lights
|
|
187
|
-
class ColorLogicSpeed(
|
|
187
|
+
class ColorLogicSpeed(PrettyEnum, IntEnum):
|
|
188
188
|
ONE_SIXTEENTH = 0
|
|
189
189
|
ONE_EIGHTH = 1
|
|
190
190
|
ONE_QUARTER = 2
|
|
@@ -196,7 +196,7 @@ class ColorLogicSpeed(IntEnum, PrettyEnum):
|
|
|
196
196
|
SIXTEEN_TIMES = 8
|
|
197
197
|
|
|
198
198
|
|
|
199
|
-
class ColorLogicBrightness(
|
|
199
|
+
class ColorLogicBrightness(PrettyEnum, IntEnum):
|
|
200
200
|
TWENTY_PERCENT = 0
|
|
201
201
|
FOURTY_PERCENT = 1
|
|
202
202
|
SIXTY_PERCENT = 2
|
|
@@ -207,7 +207,7 @@ class ColorLogicBrightness(IntEnum, PrettyEnum):
|
|
|
207
207
|
type LightShows = ColorLogicShow25 | ColorLogicShow40 | ColorLogicShowUCL | ColorLogicShowUCLV2 | PentairShow | ZodiacShow
|
|
208
208
|
|
|
209
209
|
|
|
210
|
-
class ColorLogicShow25(
|
|
210
|
+
class ColorLogicShow25(PrettyEnum, IntEnum):
|
|
211
211
|
VOODOO_LOUNGE = 0
|
|
212
212
|
DEEP_BLUE_SEA = 1
|
|
213
213
|
AFTERNOON_SKY = 2
|
|
@@ -222,7 +222,7 @@ class ColorLogicShow25(IntEnum, PrettyEnum):
|
|
|
222
222
|
COOL_CABARET = 11
|
|
223
223
|
|
|
224
224
|
|
|
225
|
-
class ColorLogicShow40(
|
|
225
|
+
class ColorLogicShow40(PrettyEnum, IntEnum):
|
|
226
226
|
VOODOO_LOUNGE = 0
|
|
227
227
|
DEEP_BLUE_SEA = 1
|
|
228
228
|
AFTERNOON_SKY = 2
|
|
@@ -237,7 +237,7 @@ class ColorLogicShow40(IntEnum, PrettyEnum):
|
|
|
237
237
|
COOL_CABARET = 11
|
|
238
238
|
|
|
239
239
|
|
|
240
|
-
class ColorLogicShowUCL(
|
|
240
|
+
class ColorLogicShowUCL(PrettyEnum, IntEnum):
|
|
241
241
|
VOODOO_LOUNGE = 0
|
|
242
242
|
DEEP_BLUE_SEA = 1
|
|
243
243
|
ROYAL_BLUE = 2
|
|
@@ -257,7 +257,7 @@ class ColorLogicShowUCL(IntEnum, PrettyEnum):
|
|
|
257
257
|
COOL_CABARET = 16
|
|
258
258
|
|
|
259
259
|
|
|
260
|
-
class ColorLogicShowUCLV2(
|
|
260
|
+
class ColorLogicShowUCLV2(PrettyEnum, IntEnum):
|
|
261
261
|
VOODOO_LOUNGE = 0
|
|
262
262
|
DEEP_BLUE_SEA = 1
|
|
263
263
|
ROYAL_BLUE = 2
|
|
@@ -288,7 +288,7 @@ class ColorLogicShowUCLV2(IntEnum, PrettyEnum):
|
|
|
288
288
|
BRIGHT_YELLOW = 26
|
|
289
289
|
|
|
290
290
|
|
|
291
|
-
class PentairShow(
|
|
291
|
+
class PentairShow(PrettyEnum, IntEnum):
|
|
292
292
|
SAM = 0
|
|
293
293
|
PARTY = 1
|
|
294
294
|
ROMANCE = 2
|
|
@@ -303,7 +303,7 @@ class PentairShow(IntEnum, PrettyEnum):
|
|
|
303
303
|
MAGENTA = 11
|
|
304
304
|
|
|
305
305
|
|
|
306
|
-
class ZodiacShow(
|
|
306
|
+
class ZodiacShow(PrettyEnum, IntEnum):
|
|
307
307
|
ALPINE_WHITE = 0
|
|
308
308
|
SKY_BLUE = 1
|
|
309
309
|
COBALT_BLUE = 2
|
|
@@ -320,7 +320,7 @@ class ZodiacShow(IntEnum, PrettyEnum):
|
|
|
320
320
|
DISCO_TECH = 13
|
|
321
321
|
|
|
322
322
|
|
|
323
|
-
class ColorLogicPowerState(
|
|
323
|
+
class ColorLogicPowerState(PrettyEnum, IntEnum):
|
|
324
324
|
OFF = 0
|
|
325
325
|
POWERING_OFF = 1
|
|
326
326
|
CHANGING_SHOW = 3
|
|
@@ -329,7 +329,7 @@ class ColorLogicPowerState(IntEnum, PrettyEnum):
|
|
|
329
329
|
COOLDOWN = 7
|
|
330
330
|
|
|
331
331
|
|
|
332
|
-
class ColorLogicLightType(
|
|
332
|
+
class ColorLogicLightType(PrettyEnum, StrEnum):
|
|
333
333
|
UCL = "COLOR_LOGIC_UCL"
|
|
334
334
|
FOUR_ZERO = "COLOR_LOGIC_4_0"
|
|
335
335
|
TWO_FIVE = "COLOR_LOGIC_2_5"
|
|
@@ -342,22 +342,22 @@ class ColorLogicLightType(StrEnum, PrettyEnum):
|
|
|
342
342
|
return ColorLogicLightType[self.name].value
|
|
343
343
|
|
|
344
344
|
|
|
345
|
-
class CSADType(
|
|
345
|
+
class CSADType(PrettyEnum, StrEnum):
|
|
346
346
|
ACID = "ACID"
|
|
347
347
|
CO2 = "CO2"
|
|
348
348
|
|
|
349
349
|
|
|
350
|
-
class CSADEquipmentType(
|
|
350
|
+
class CSADEquipmentType(PrettyEnum, StrEnum):
|
|
351
351
|
AQL_CHEM = "AQL-CHEM"
|
|
352
352
|
|
|
353
353
|
|
|
354
354
|
# Chemistry Sense and Dispense
|
|
355
|
-
class CSADStatus(
|
|
355
|
+
class CSADStatus(PrettyEnum, IntEnum):
|
|
356
356
|
NOT_DISPENSING = 0
|
|
357
357
|
DISPENSING = 1
|
|
358
358
|
|
|
359
359
|
|
|
360
|
-
class CSADMode(
|
|
360
|
+
class CSADMode(PrettyEnum, IntEnum):
|
|
361
361
|
OFF = 0
|
|
362
362
|
AUTO = 1
|
|
363
363
|
FORCE_ON = 2
|
|
@@ -366,7 +366,7 @@ class CSADMode(IntEnum, PrettyEnum):
|
|
|
366
366
|
|
|
367
367
|
|
|
368
368
|
# Filters
|
|
369
|
-
class FilterState(
|
|
369
|
+
class FilterState(PrettyEnum, IntEnum):
|
|
370
370
|
OFF = 0
|
|
371
371
|
ON = 1
|
|
372
372
|
PRIMING = 2
|
|
@@ -381,13 +381,13 @@ class FilterState(IntEnum, PrettyEnum):
|
|
|
381
381
|
FILTER_WAITING_TURN_OFF = 11
|
|
382
382
|
|
|
383
383
|
|
|
384
|
-
class FilterType(
|
|
384
|
+
class FilterType(PrettyEnum, StrEnum):
|
|
385
385
|
VARIABLE_SPEED = "FMT_VARIABLE_SPEED_PUMP"
|
|
386
386
|
DUAL_SPEED = "FMT_DUAL_SPEED"
|
|
387
387
|
SINGLE_SPEED = "FMT_SINGLE_SPEED"
|
|
388
388
|
|
|
389
389
|
|
|
390
|
-
class FilterValvePosition(
|
|
390
|
+
class FilterValvePosition(PrettyEnum, IntEnum):
|
|
391
391
|
POOL_ONLY = 1
|
|
392
392
|
SPA_ONLY = 2
|
|
393
393
|
SPILLOVER = 3
|
|
@@ -395,7 +395,7 @@ class FilterValvePosition(IntEnum, PrettyEnum):
|
|
|
395
395
|
HIGH_PRIO_HEAT = 5
|
|
396
396
|
|
|
397
397
|
|
|
398
|
-
class FilterWhyOn(
|
|
398
|
+
class FilterWhyOn(PrettyEnum, IntEnum):
|
|
399
399
|
OFF = 0
|
|
400
400
|
NO_WATER_FLOW = 1
|
|
401
401
|
COOLDOWN = 2
|
|
@@ -417,28 +417,30 @@ class FilterWhyOn(IntEnum, PrettyEnum):
|
|
|
417
417
|
GROUP_COMMAND = 18
|
|
418
418
|
SPILLOVER_INTERLOCK = 19
|
|
419
419
|
MAX_VALUE = 20
|
|
420
|
+
UNKNOWN_1 = 21
|
|
421
|
+
UNKNOWN_2 = 22
|
|
420
422
|
|
|
421
423
|
|
|
422
|
-
class FilterSpeedPresets(
|
|
424
|
+
class FilterSpeedPresets(PrettyEnum, StrEnum):
|
|
423
425
|
LOW = auto()
|
|
424
426
|
MEDIUM = auto()
|
|
425
427
|
HIGH = auto()
|
|
426
428
|
|
|
427
429
|
|
|
428
430
|
# Groups
|
|
429
|
-
class GroupState(
|
|
431
|
+
class GroupState(PrettyEnum, IntEnum):
|
|
430
432
|
OFF = 0
|
|
431
433
|
ON = 1
|
|
432
434
|
|
|
433
435
|
|
|
434
436
|
# Heaters
|
|
435
|
-
class HeaterState(
|
|
437
|
+
class HeaterState(PrettyEnum, IntEnum):
|
|
436
438
|
OFF = 0
|
|
437
439
|
ON = 1
|
|
438
440
|
PAUSE = 2
|
|
439
441
|
|
|
440
442
|
|
|
441
|
-
class HeaterType(
|
|
443
|
+
class HeaterType(PrettyEnum, StrEnum):
|
|
442
444
|
GAS = "HTR_GAS"
|
|
443
445
|
HEAT_PUMP = "HTR_HEAT_PUMP"
|
|
444
446
|
SOLAR = "HTR_SOLAR"
|
|
@@ -449,26 +451,26 @@ class HeaterType(StrEnum, PrettyEnum):
|
|
|
449
451
|
SMART_HEAT_PUMP = "HTR_SMART_HEAT_PUMP"
|
|
450
452
|
|
|
451
453
|
|
|
452
|
-
class HeaterMode(
|
|
454
|
+
class HeaterMode(PrettyEnum, IntEnum):
|
|
453
455
|
HEAT = 0
|
|
454
456
|
COOL = 1
|
|
455
457
|
AUTO = 2
|
|
456
458
|
|
|
457
459
|
|
|
458
460
|
# Pumps
|
|
459
|
-
class PumpState(
|
|
461
|
+
class PumpState(PrettyEnum, IntEnum):
|
|
460
462
|
OFF = 0
|
|
461
463
|
ON = 1
|
|
462
464
|
FREEZE_PROTECT = 2 # This is an assumption that 2 means freeze protect, ref: https://github.com/cryptk/haomnilogic-local/issues/147
|
|
463
465
|
|
|
464
466
|
|
|
465
|
-
class PumpType(
|
|
467
|
+
class PumpType(PrettyEnum, StrEnum):
|
|
466
468
|
SINGLE_SPEED = "PMP_SINGLE_SPEED"
|
|
467
469
|
DUAL_SPEED = "PMP_DUAL_SPEED"
|
|
468
470
|
VARIABLE_SPEED = "PMP_VARIABLE_SPEED_PUMP"
|
|
469
471
|
|
|
470
472
|
|
|
471
|
-
class PumpFunction(
|
|
473
|
+
class PumpFunction(PrettyEnum, StrEnum):
|
|
472
474
|
PUMP = "PMP_PUMP"
|
|
473
475
|
WATER_FEATURE = "PMP_WATER_FEATURE"
|
|
474
476
|
CLEANER = "PMP_CLEANER"
|
|
@@ -485,14 +487,14 @@ class PumpFunction(StrEnum, PrettyEnum):
|
|
|
485
487
|
CLEANER_IN_FLOOR = "PMP_CLEANER_IN_FLOOR"
|
|
486
488
|
|
|
487
489
|
|
|
488
|
-
class PumpSpeedPresets(
|
|
490
|
+
class PumpSpeedPresets(PrettyEnum, StrEnum):
|
|
489
491
|
LOW = auto()
|
|
490
492
|
MEDIUM = auto()
|
|
491
493
|
HIGH = auto()
|
|
492
494
|
|
|
493
495
|
|
|
494
496
|
# Relays
|
|
495
|
-
class RelayFunction(
|
|
497
|
+
class RelayFunction(PrettyEnum, StrEnum):
|
|
496
498
|
WATER_FEATURE = "RLY_WATER_FEATURE"
|
|
497
499
|
LIGHT = "RLY_LIGHT"
|
|
498
500
|
BACKYARD_LIGHT = "RLY_BACKYARD_LIGHT"
|
|
@@ -512,18 +514,18 @@ class RelayFunction(StrEnum, PrettyEnum):
|
|
|
512
514
|
CLEANER_IN_FLOOR = "RLY_CLEANER_IN_FLOOR"
|
|
513
515
|
|
|
514
516
|
|
|
515
|
-
class RelayState(
|
|
517
|
+
class RelayState(PrettyEnum, IntEnum):
|
|
516
518
|
OFF = 0
|
|
517
519
|
ON = 1
|
|
518
520
|
|
|
519
521
|
|
|
520
|
-
class RelayType(
|
|
522
|
+
class RelayType(PrettyEnum, StrEnum):
|
|
521
523
|
VALVE_ACTUATOR = "RLY_VALVE_ACTUATOR"
|
|
522
524
|
HIGH_VOLTAGE = "RLY_HIGH_VOLTAGE_RELAY"
|
|
523
525
|
LOW_VOLTAGE = "RLY_LOW_VOLTAGE_RELAY"
|
|
524
526
|
|
|
525
527
|
|
|
526
|
-
class RelayWhyOn(
|
|
528
|
+
class RelayWhyOn(PrettyEnum, IntEnum):
|
|
527
529
|
NO_MESSAGE = 0
|
|
528
530
|
MANUAL_OFF = 1
|
|
529
531
|
COUNTDOWN_DONE = 2
|
|
@@ -539,7 +541,7 @@ class RelayWhyOn(IntEnum, PrettyEnum):
|
|
|
539
541
|
|
|
540
542
|
|
|
541
543
|
# Sensors
|
|
542
|
-
class SensorType(
|
|
544
|
+
class SensorType(PrettyEnum, StrEnum):
|
|
543
545
|
AIR_TEMP = "SENSOR_AIR_TEMP"
|
|
544
546
|
SOLAR_TEMP = "SENSOR_SOLAR_TEMP"
|
|
545
547
|
WATER_TEMP = "SENSOR_WATER_TEMP"
|
|
@@ -548,7 +550,7 @@ class SensorType(StrEnum, PrettyEnum):
|
|
|
548
550
|
EXT_INPUT = "SENSOR_EXT_INPUT"
|
|
549
551
|
|
|
550
552
|
|
|
551
|
-
class SensorUnits(
|
|
553
|
+
class SensorUnits(PrettyEnum, StrEnum):
|
|
552
554
|
FAHRENHEIT = "UNITS_FAHRENHEIT"
|
|
553
555
|
CELSIUS = "UNITS_CELSIUS"
|
|
554
556
|
PPM = "UNITS_PPM"
|
|
@@ -559,13 +561,13 @@ class SensorUnits(StrEnum, PrettyEnum):
|
|
|
559
561
|
|
|
560
562
|
|
|
561
563
|
# Valve Actuators
|
|
562
|
-
class ValveActuatorState(
|
|
564
|
+
class ValveActuatorState(PrettyEnum, IntEnum):
|
|
563
565
|
OFF = 0
|
|
564
566
|
ON = 1
|
|
565
567
|
|
|
566
568
|
|
|
567
569
|
# Schedules
|
|
568
|
-
class ScheduleDaysActive(
|
|
570
|
+
class ScheduleDaysActive(PrettyEnum, Flag):
|
|
569
571
|
MONDAY = 1 << 0
|
|
570
572
|
TUESDAY = 1 << 1
|
|
571
573
|
WEDNESDAY = 1 << 2
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
from typing import TYPE_CHECKING
|
|
4
|
+
|
|
3
5
|
from pyomnilogic_local._base import OmniEquipment
|
|
4
6
|
from pyomnilogic_local.decorators import control_method
|
|
5
7
|
from pyomnilogic_local.models.mspconfig import MSPPump
|
|
@@ -7,6 +9,9 @@ from pyomnilogic_local.models.telemetry import TelemetryPump
|
|
|
7
9
|
from pyomnilogic_local.omnitypes import PumpSpeedPresets, PumpState
|
|
8
10
|
from pyomnilogic_local.util import OmniEquipmentNotInitializedError
|
|
9
11
|
|
|
12
|
+
if TYPE_CHECKING:
|
|
13
|
+
from pyomnilogic_local.omnitypes import PumpFunction, PumpType
|
|
14
|
+
|
|
10
15
|
|
|
11
16
|
class Pump(OmniEquipment[MSPPump, TelemetryPump]):
|
|
12
17
|
"""Represents a pump in the OmniLogic system.
|
|
@@ -80,12 +85,12 @@ class Pump(OmniEquipment[MSPPump, TelemetryPump]):
|
|
|
80
85
|
|
|
81
86
|
# Expose MSPConfig attributes
|
|
82
87
|
@property
|
|
83
|
-
def equip_type(self) ->
|
|
88
|
+
def equip_type(self) -> PumpType:
|
|
84
89
|
"""The pump type (e.g., PMP_VARIABLE_SPEED_PUMP)."""
|
|
85
90
|
return self.mspconfig.equip_type
|
|
86
91
|
|
|
87
92
|
@property
|
|
88
|
-
def function(self) ->
|
|
93
|
+
def function(self) -> PumpFunction:
|
|
89
94
|
"""The pump function (e.g., PMP_PUMP, PMP_WATER_FEATURE)."""
|
|
90
95
|
return self.mspconfig.function
|
|
91
96
|
|
|
@@ -131,7 +136,7 @@ class Pump(OmniEquipment[MSPPump, TelemetryPump]):
|
|
|
131
136
|
|
|
132
137
|
# Expose Telemetry attributes
|
|
133
138
|
@property
|
|
134
|
-
def state(self) -> PumpState
|
|
139
|
+
def state(self) -> PumpState:
|
|
135
140
|
"""Current pump state."""
|
|
136
141
|
return self.telemetry.state
|
|
137
142
|
|
|
@@ -147,7 +152,10 @@ class Pump(OmniEquipment[MSPPump, TelemetryPump]):
|
|
|
147
152
|
|
|
148
153
|
@property
|
|
149
154
|
def why_on(self) -> int:
|
|
150
|
-
"""Reason why the pump is on.
|
|
155
|
+
"""Reason why the pump is on.
|
|
156
|
+
|
|
157
|
+
We don't have a confirmation that these are the same as the FilterWhyOn states yet.
|
|
158
|
+
"""
|
|
151
159
|
return self.telemetry.why_on
|
|
152
160
|
|
|
153
161
|
# Computed properties
|
|
@@ -86,7 +86,7 @@ class Sensor(OmniEquipment[MSPSensor, None]):
|
|
|
86
86
|
super().__init__(omni, mspconfig, telemetry)
|
|
87
87
|
|
|
88
88
|
@property
|
|
89
|
-
def equip_type(self) -> SensorType
|
|
89
|
+
def equip_type(self) -> SensorType:
|
|
90
90
|
"""Returns the type of sensor.
|
|
91
91
|
|
|
92
92
|
Can be AIR_TEMP, SOLAR_TEMP, WATER_TEMP, FLOW, ORP, or EXT_INPUT.
|
|
@@ -94,7 +94,7 @@ class Sensor(OmniEquipment[MSPSensor, None]):
|
|
|
94
94
|
return self.mspconfig.equip_type
|
|
95
95
|
|
|
96
96
|
@property
|
|
97
|
-
def units(self) -> SensorUnits
|
|
97
|
+
def units(self) -> SensorUnits:
|
|
98
98
|
"""Returns the units used by the sensor.
|
|
99
99
|
|
|
100
100
|
Can be FAHRENHEIT, CELSIUS, PPM, GRAMS_PER_LITER, MILLIVOLTS,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
from typing import TYPE_CHECKING
|
|
3
|
+
from typing import TYPE_CHECKING, Literal
|
|
4
4
|
|
|
5
5
|
if TYPE_CHECKING:
|
|
6
6
|
from pyomnilogic_local.models.mspconfig import MSPSystem
|
|
@@ -15,12 +15,12 @@ class System:
|
|
|
15
15
|
self.update_config(mspconfig)
|
|
16
16
|
|
|
17
17
|
@property
|
|
18
|
-
def vsp_speed_format(self) ->
|
|
18
|
+
def vsp_speed_format(self) -> Literal["RPM", "Percent"]:
|
|
19
19
|
"""The VSP speed format of the system."""
|
|
20
20
|
return self.mspconfig.vsp_speed_format
|
|
21
21
|
|
|
22
22
|
@property
|
|
23
|
-
def units(self) ->
|
|
23
|
+
def units(self) -> Literal["Standard", "Metric"]:
|
|
24
24
|
"""The units of the system."""
|
|
25
25
|
return self.mspconfig.units
|
|
26
26
|
|
|
@@ -40,9 +40,15 @@ class OmniConnectionError(OmniLogicLocalError):
|
|
|
40
40
|
|
|
41
41
|
|
|
42
42
|
class PrettyEnum(Enum):
|
|
43
|
-
def
|
|
43
|
+
def __str__(self) -> str:
|
|
44
|
+
"""Return a human-friendly string representation of the enum member."""
|
|
44
45
|
return self.name.replace("_", " ").title()
|
|
45
46
|
|
|
46
47
|
@classmethod
|
|
47
|
-
def
|
|
48
|
-
|
|
48
|
+
def from_str(cls, name: str) -> Self:
|
|
49
|
+
lookup_key = name.upper().replace(" ", "_")
|
|
50
|
+
try:
|
|
51
|
+
return cls[lookup_key]
|
|
52
|
+
except KeyError as err:
|
|
53
|
+
msg = f"'{name}' is not a valid {cls.__name__}"
|
|
54
|
+
raise ValueError(msg) from err
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "python-omnilogic-local"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.25.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"
|
|
@@ -12,7 +12,6 @@ authors = [
|
|
|
12
12
|
license-files = ["LICENSE"]
|
|
13
13
|
dependencies = [
|
|
14
14
|
"pydantic >=2.0.0,<3.0.0",
|
|
15
|
-
"click >=8.0.0,<9.0.0",
|
|
16
15
|
"xmltodict >=1.0.1,<2.0.0",
|
|
17
16
|
]
|
|
18
17
|
|
|
@@ -22,6 +21,7 @@ omnilogic = "pyomnilogic_local.cli.cli:entrypoint"
|
|
|
22
21
|
[project.optional-dependencies]
|
|
23
22
|
cli = [
|
|
24
23
|
"scapy>=2.6.1,<3.0.0",
|
|
24
|
+
"click >=8.0.0,<9.0.0",
|
|
25
25
|
]
|
|
26
26
|
build = [
|
|
27
27
|
"uv ~= 0.11.6"
|
|
File without changes
|
|
File without changes
|
{python_omnilogic_local-0.23.0 → python_omnilogic_local-0.25.0}/pyomnilogic_local/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{python_omnilogic_local-0.23.0 → python_omnilogic_local-0.25.0}/pyomnilogic_local/api/__init__.py
RENAMED
|
File without changes
|
{python_omnilogic_local-0.23.0 → python_omnilogic_local-0.25.0}/pyomnilogic_local/api/constants.py
RENAMED
|
File without changes
|
{python_omnilogic_local-0.23.0 → python_omnilogic_local-0.25.0}/pyomnilogic_local/api/exceptions.py
RENAMED
|
File without changes
|
{python_omnilogic_local-0.23.0 → python_omnilogic_local-0.25.0}/pyomnilogic_local/api/mock_api.py
RENAMED
|
File without changes
|
{python_omnilogic_local-0.23.0 → python_omnilogic_local-0.25.0}/pyomnilogic_local/api/protocol.py
RENAMED
|
File without changes
|
{python_omnilogic_local-0.23.0 → python_omnilogic_local-0.25.0}/pyomnilogic_local/backyard.py
RENAMED
|
File without changes
|
{python_omnilogic_local-0.23.0 → python_omnilogic_local-0.25.0}/pyomnilogic_local/chlorinator.py
RENAMED
|
File without changes
|
|
File without changes
|
{python_omnilogic_local-0.23.0 → python_omnilogic_local-0.25.0}/pyomnilogic_local/cli/__init__.py
RENAMED
|
File without changes
|
{python_omnilogic_local-0.23.0 → python_omnilogic_local-0.25.0}/pyomnilogic_local/cli/cli.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_omnilogic_local-0.23.0 → python_omnilogic_local-0.25.0}/pyomnilogic_local/cli/pcap_utils.py
RENAMED
|
File without changes
|
{python_omnilogic_local-0.23.0 → python_omnilogic_local-0.25.0}/pyomnilogic_local/cli/utils.py
RENAMED
|
File without changes
|
{python_omnilogic_local-0.23.0 → python_omnilogic_local-0.25.0}/pyomnilogic_local/collections.py
RENAMED
|
File without changes
|
{python_omnilogic_local-0.23.0 → python_omnilogic_local-0.25.0}/pyomnilogic_local/colorlogiclight.py
RENAMED
|
File without changes
|
{python_omnilogic_local-0.23.0 → python_omnilogic_local-0.25.0}/pyomnilogic_local/csad_equip.py
RENAMED
|
File without changes
|
{python_omnilogic_local-0.23.0 → python_omnilogic_local-0.25.0}/pyomnilogic_local/decorators.py
RENAMED
|
File without changes
|
|
File without changes
|
{python_omnilogic_local-0.23.0 → python_omnilogic_local-0.25.0}/pyomnilogic_local/models/__init__.py
RENAMED
|
File without changes
|
{python_omnilogic_local-0.23.0 → python_omnilogic_local-0.25.0}/pyomnilogic_local/models/const.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_omnilogic_local-0.23.0 → python_omnilogic_local-0.25.0}/pyomnilogic_local/omnilogic.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_omnilogic_local-0.23.0 → python_omnilogic_local-0.25.0}/pyomnilogic_local/schedule.py
RENAMED
|
File without changes
|