Skip to content

Commit 3b29d69

Browse files
committed
feat: add CSAD pH and ORP control to API layer and CLI
1 parent 5c93dd5 commit 3b29d69

File tree

3 files changed

+131
-0
lines changed

3 files changed

+131
-0
lines changed

pyomnilogic_local/api/api.py

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -540,6 +540,54 @@ async def async_set_chlorinator_enable(self, pool_id: int, enabled: int | bool)
540540

541541
return await self.async_send_message(MessageType.SET_CHLOR_ENABLED, req_body, False)
542542

543+
# This is used to set the ORP target value on a CSAD
544+
async def async_set_csad_orp_target_level(
545+
self,
546+
pool_id: int,
547+
csad_id: int,
548+
orp_target: int,
549+
) -> None:
550+
body_element = ET.Element("Request", {"xmlns": XML_NAMESPACE})
551+
552+
name_element = ET.SubElement(body_element, "Name")
553+
name_element.text = "SetUICSADORPTargetLevel"
554+
555+
parameters_element = ET.SubElement(body_element, "Parameters")
556+
parameter = ET.SubElement(parameters_element, "Parameter", name="PoolId", dataType="int")
557+
parameter.text = str(pool_id)
558+
parameter = ET.SubElement(parameters_element, "Parameter", name="CSADID", dataType="int", alias="EquipmentID")
559+
parameter.text = str(csad_id)
560+
parameter = ET.SubElement(parameters_element, "Parameter", name="ORPTargetValue", dataType="byte", alias="Data1")
561+
parameter.text = str(orp_target)
562+
563+
req_body = ET.tostring(body_element, xml_declaration=True, encoding=XML_ENCODING)
564+
565+
return await self.async_send_message(MessageType.SET_CSAD_ORP_TARGET, req_body, False)
566+
567+
# This is used to set the pH target value on a CSAD
568+
async def async_set_csad_target_value(
569+
self,
570+
pool_id: int,
571+
csad_id: int,
572+
ph_target: float,
573+
) -> None:
574+
body_element = ET.Element("Request", {"xmlns": XML_NAMESPACE})
575+
576+
name_element = ET.SubElement(body_element, "Name")
577+
name_element.text = "UISetCSADTargetValue"
578+
579+
parameters_element = ET.SubElement(body_element, "Parameters")
580+
parameter = ET.SubElement(parameters_element, "Parameter", name="PoolId", dataType="int")
581+
parameter.text = str(pool_id)
582+
parameter = ET.SubElement(parameters_element, "Parameter", name="CSADID", dataType="int", alias="EquipmentID")
583+
parameter.text = str(csad_id)
584+
parameter = ET.SubElement(parameters_element, "Parameter", name="TargetValue", dataType="float", alias="Data1")
585+
parameter.text = str(ph_target)
586+
587+
req_body = ET.tostring(body_element, xml_declaration=True, encoding=XML_ENCODING)
588+
589+
return await self.async_send_message(MessageType.SET_CSAD_TARGET_VALUE, req_body, False)
590+
543591
async def async_set_chlorinator_params(
544592
self,
545593
pool_id: int,

pyomnilogic_local/cli/debug/commands.py

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -319,3 +319,82 @@ def set_chlor_params(ctx: click.Context, bow_id: int, equip_id: int, timed_perce
319319
except Exception as e:
320320
click.echo(f"Error setting chlorinator parameters: {e}", err=True)
321321
raise click.Abort from e
322+
323+
324+
@debug.command()
325+
@click.argument("bow_id", type=int)
326+
@click.argument("csad_id", type=int)
327+
@click.argument("target", type=float)
328+
@click.pass_context
329+
def set_csad_ph(ctx: click.Context, bow_id: int, csad_id: int, target: float) -> None:
330+
"""Set the pH target value for a CSAD (Chemical Sense and Dispense).
331+
332+
This command sets the target pH level that the CSAD will attempt to maintain.
333+
334+
BOW_ID: The Body of Water (pool/spa) system ID
335+
CSAD_ID: The CSAD equipment system ID
336+
TARGET: Target pH value (typically 7.0-8.0)
337+
338+
Examples:
339+
# Set pH target to 7.4
340+
omnilogic --host 192.168.1.100 debug set-csad-ph 7 20 7.4
341+
342+
# Set pH target to 7.2
343+
omnilogic --host 192.168.1.100 debug set-csad-ph 7 20 7.2
344+
345+
"""
346+
ensure_connection(ctx)
347+
omni: OmniLogicAPI = ctx.obj["OMNI"]
348+
349+
# Validate target pH (typical range is 6.8-8.2, but allow wider range)
350+
if not 0.0 <= target <= 14.0:
351+
click.echo(f"Error: pH target must be between 0.0-14.0, got {target}", err=True)
352+
raise click.Abort
353+
354+
# Execute the command
355+
try:
356+
asyncio.run(omni.async_set_csad_target_value(pool_id=bow_id, csad_id=csad_id, ph_target=target))
357+
click.echo(f"Successfully set CSAD {csad_id} in BOW {bow_id} pH target to {target}")
358+
except Exception as e:
359+
click.echo(f"Error setting CSAD pH target: {e}", err=True)
360+
raise click.Abort from e
361+
362+
363+
@debug.command()
364+
@click.argument("bow_id", type=int)
365+
@click.argument("csad_id", type=int)
366+
@click.argument("target", type=int)
367+
@click.pass_context
368+
def set_csad_orp(ctx: click.Context, bow_id: int, csad_id: int, target: int) -> None:
369+
"""Set the ORP target level for a CSAD (Chemical Sense and Dispense).
370+
371+
This command sets the target ORP (Oxidation-Reduction Potential) level in
372+
millivolts that the CSAD will attempt to maintain.
373+
374+
BOW_ID: The Body of Water (pool/spa) system ID
375+
CSAD_ID: The CSAD equipment system ID
376+
TARGET: Target ORP value in millivolts (typically 600-800 mV)
377+
378+
Examples:
379+
# Set ORP target to 700 mV
380+
omnilogic --host 192.168.1.100 debug set-csad-orp 7 20 700
381+
382+
# Set ORP target to 650 mV
383+
omnilogic --host 192.168.1.100 debug set-csad-orp 7 20 650
384+
385+
"""
386+
ensure_connection(ctx)
387+
omni: OmniLogicAPI = ctx.obj["OMNI"]
388+
389+
# Validate target ORP (typical range is 400-900 mV, but allow 0-1000)
390+
if not 0 <= target <= 1000:
391+
click.echo(f"Error: ORP target must be between 0-1000 mV, got {target}", err=True)
392+
raise click.Abort
393+
394+
# Execute the command
395+
try:
396+
asyncio.run(omni.async_set_csad_orp_target_level(pool_id=bow_id, csad_id=csad_id, orp_target=target))
397+
click.echo(f"Successfully set CSAD {csad_id} in BOW {bow_id} ORP target to {target} mV")
398+
except Exception as e:
399+
click.echo(f"Error setting CSAD ORP target: {e}", err=True)
400+
raise click.Abort from e

pyomnilogic_local/omnitypes.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,10 @@ class MessageType(IntEnum, PrettyEnum):
2121
CREATE_SCHEDULE = 230
2222
DELETE_SCHEDULE = 231
2323
EDIT_SCHEDULE = 233
24+
SET_CSAD_TARGET_VALUE = 253
25+
SET_CSAD_ORP_TARGET = 281
2426
GET_TELEMETRY = 300
27+
GET_ALARM_LIST = 304
2528
SET_STANDALONE_LIGHT_SHOW = 308
2629
SET_SPILLOVER = 311
2730
RUN_GROUP_CMD = 317
@@ -31,6 +34,7 @@ class MessageType(IntEnum, PrettyEnum):
3134
ACK = 1002
3235
MSP_TELEMETRY_UPDATE = 1004
3336
MSP_CONFIGURATIONUPDATE = 1003
37+
MSP_ALARM_LIST_RESPONSE = 1304
3438
MSP_LEADMESSAGE = 1998
3539
MSP_BLOCKMESSAGE = 1999
3640

0 commit comments

Comments
 (0)