Skip to content

Commit 6410c81

Browse files
authored
feat: begin to add new CLI utility, ref #66 (#67)
1 parent 4030767 commit 6410c81

File tree

12 files changed

+210
-9
lines changed

12 files changed

+210
-9
lines changed

.pre-commit-config.yaml

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,11 +40,14 @@ repos:
4040
- id: ruff
4141
args:
4242
- --fix
43-
- repo: https://github.com/pylint-dev/pylint
44-
rev: v3.3.3
43+
- repo: local
4544
hooks:
4645
- id: pylint
47-
additional_dependencies: [ "pydantic>=1.10.17", "xmltodict" ]
46+
name: pylint
47+
entry: poetry run pylint
48+
language: system
49+
types: [python]
50+
require_serial: true
4851
- repo: https://github.com/pre-commit/mirrors-mypy
4952
rev: v1.14.1
5053
hooks:

poetry.lock

Lines changed: 18 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyomnilogic_local/cli/__init__.py

Whitespace-only changes.

pyomnilogic_local/cli/cli.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import asyncio
2+
3+
import click
4+
5+
from pyomnilogic_local.api import OmniLogicAPI
6+
from pyomnilogic_local.cli.debug import commands as debug
7+
from pyomnilogic_local.cli.get import commands as get
8+
9+
10+
async def get_omni(host: str) -> OmniLogicAPI:
11+
return OmniLogicAPI(host, 10444, 5.0)
12+
13+
14+
@click.group()
15+
@click.pass_context
16+
@click.option("--host", default="127.0.0.1", help="Hostname or IP address of omnilogic system")
17+
def entrypoint(ctx: click.Context, host: str) -> None:
18+
ctx.ensure_object(dict)
19+
omni = asyncio.run(get_omni(host))
20+
21+
ctx.obj["OMNI"] = omni
22+
23+
24+
entrypoint.add_command(debug.debug)
25+
entrypoint.add_command(get.get)

pyomnilogic_local/cli/debug/__init__.py

Whitespace-only changes.
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
# Need to figure out how to resolve the 'Untyped decorator makes function "..." untyped' errors in mypy when using click decorators
2+
# mypy: disable-error-code="misc"
3+
import asyncio
4+
from typing import Literal, overload
5+
6+
import click
7+
8+
from pyomnilogic_local.api import OmniLogicAPI
9+
from pyomnilogic_local.cli.utils import async_get_mspconfig, async_get_telemetry
10+
from pyomnilogic_local.models.filter_diagnostics import FilterDiagnostics
11+
12+
13+
@click.group()
14+
@click.option("--raw/--no-raw", default=False, help="Output the raw XML from the OmniLogic, do not parse the response")
15+
@click.pass_context
16+
def debug(ctx: click.Context, raw: bool) -> None:
17+
# Container for all get commands
18+
19+
ctx.ensure_object(dict)
20+
ctx.obj["RAW"] = raw
21+
22+
23+
@debug.command()
24+
@click.pass_context
25+
def get_mspconfig(ctx: click.Context) -> None:
26+
mspconfig = asyncio.run(async_get_mspconfig(ctx.obj["OMNI"], ctx.obj["RAW"]))
27+
click.echo(mspconfig)
28+
29+
30+
@debug.command()
31+
@click.pass_context
32+
def get_telemetry(ctx: click.Context) -> None:
33+
telemetry = asyncio.run(async_get_telemetry(ctx.obj["OMNI"], ctx.obj["RAW"]))
34+
click.echo(telemetry)
35+
36+
37+
@debug.command()
38+
@click.pass_context
39+
def get_alarm_list(ctx: click.Context) -> None:
40+
alarm_list = asyncio.run(async_get_alarm_list(ctx.obj["OMNI"]))
41+
click.echo(alarm_list)
42+
43+
44+
async def async_get_alarm_list(omni: OmniLogicAPI) -> str:
45+
alarm_list = await omni.async_get_alarm_list()
46+
return alarm_list
47+
48+
49+
@debug.command()
50+
@click.option("--pool-id", help="System ID of the Body Of Water the filter is associated with")
51+
@click.option("--filter-id", help="System ID of the filter to request diagnostics for")
52+
@click.pass_context
53+
def get_filter_diagnostics(ctx: click.Context, pool_id: int, filter_id: int) -> None:
54+
filter_diags = asyncio.run(async_get_filter_diagnostics(ctx.obj["OMNI"], pool_id, filter_id, ctx.obj["RAW"]))
55+
if ctx.obj["RAW"]:
56+
click.echo(filter_diags)
57+
else:
58+
drv1 = chr(filter_diags.get_param_by_name("DriveFWRevisionB1"))
59+
drv2 = chr(filter_diags.get_param_by_name("DriveFWRevisionB2"))
60+
drv3 = chr(filter_diags.get_param_by_name("DriveFWRevisionB3"))
61+
drv4 = chr(filter_diags.get_param_by_name("DriveFWRevisionB4"))
62+
dfw1 = chr(filter_diags.get_param_by_name("DisplayFWRevisionB1"))
63+
dfw2 = chr(filter_diags.get_param_by_name("DisplayFWRevisionB2"))
64+
dfw3 = chr(filter_diags.get_param_by_name("DisplayFWRevisionB3"))
65+
dfw4 = chr(filter_diags.get_param_by_name("DisplayFWRevisionB4"))
66+
pow1 = filter_diags.get_param_by_name("PowerMSB")
67+
pow2 = filter_diags.get_param_by_name("PowerLSB")
68+
errs = filter_diags.get_param_by_name("ErrorStatus")
69+
click.echo(
70+
f"DRIVE FW REV: {drv1}{drv2}.{drv3}{drv4}\n"
71+
f"DISPLAY FW REV: {dfw1}{dfw2}.{dfw3}.{dfw4}\n"
72+
f"POWER: {pow1:x}{pow2:x}W\n"
73+
f"ERROR STATUS: {errs}"
74+
)
75+
76+
77+
@overload
78+
async def async_get_filter_diagnostics(omni: OmniLogicAPI, pool_id: int, filter_id: int, raw: Literal[True]) -> str: ...
79+
@overload
80+
async def async_get_filter_diagnostics(omni: OmniLogicAPI, pool_id: int, filter_id: int, raw: Literal[False]) -> FilterDiagnostics: ...
81+
async def async_get_filter_diagnostics(omni: OmniLogicAPI, pool_id: int, filter_id: int, raw: bool) -> FilterDiagnostics | str:
82+
filter_diags = await omni.async_get_filter_diagnostics(pool_id, filter_id, raw=raw)
83+
return filter_diags
84+
85+
86+
@debug.command()
87+
@click.pass_context
88+
def get_log_config(ctx: click.Context) -> None:
89+
log_config = asyncio.run(async_get_log_config(ctx.obj["OMNI"]))
90+
click.echo(log_config)
91+
92+
93+
async def async_get_log_config(omni: OmniLogicAPI) -> str:
94+
log_config = await omni.async_get_log_config()
95+
return log_config

pyomnilogic_local/cli/get/__init__.py

Whitespace-only changes.

pyomnilogic_local/cli/get/commands.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# Need to figure out how to resolve the 'Untyped decorator makes function "..." untyped' errors in mypy when using click decorators
2+
# mypy: disable-error-code="misc"
3+
import asyncio
4+
5+
import click
6+
7+
from pyomnilogic_local.cli.utils import async_get_mspconfig
8+
9+
10+
@click.group()
11+
@click.pass_context
12+
def get(ctx: click.Context) -> None:
13+
# Container for all get commands
14+
15+
ctx.ensure_object(dict)
16+
17+
18+
@get.command()
19+
@click.pass_context
20+
def lights(ctx: click.Context) -> None:
21+
mspconfig = asyncio.run(async_get_mspconfig(ctx.obj["OMNI"]))
22+
# Return data about lights in the backyard
23+
if mspconfig.backyard.colorlogic_light:
24+
for light in mspconfig.backyard.colorlogic_light:
25+
click.echo(light)
26+
27+
# Return data about lights in the Body of Water
28+
if mspconfig.backyard.bow:
29+
for bow in mspconfig.backyard.bow:
30+
if bow.colorlogic_light:
31+
for cl_light in bow.colorlogic_light:
32+
for k, v in cl_light:
33+
click.echo(f"{k:15}\t{str(v)}")

pyomnilogic_local/cli/utils.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
from pyomnilogic_local.api import OmniLogicAPI
2+
from pyomnilogic_local.models.mspconfig import MSPConfig
3+
from pyomnilogic_local.models.telemetry import Telemetry
4+
5+
6+
async def async_get_mspconfig(omni: OmniLogicAPI, raw: bool = False) -> MSPConfig:
7+
mspconfig: MSPConfig
8+
mspconfig = await omni.async_get_config(raw=raw)
9+
return mspconfig
10+
11+
12+
async def async_get_telemetry(omni: OmniLogicAPI, raw: bool = False) -> Telemetry:
13+
telemetry: Telemetry
14+
telemetry = await omni.async_get_telemetry(raw=raw)
15+
return telemetry
File renamed without changes.

0 commit comments

Comments
 (0)