From d93e0f662e9f24253ecc62b537798fc02715006f Mon Sep 17 00:00:00 2001 From: Chris Jowett <421501+cryptk@users.noreply.github.com> Date: Thu, 9 Jan 2025 16:04:52 -0600 Subject: [PATCH] chore: update pyproject.toml --- poetry.lock | 81 +------- pyomnilogic_local/api.py | 191 +++++++++++++++--- .../models/filter_diagnostics.py | 1 + pyomnilogic_local/models/mspconfig.py | 11 +- pyomnilogic_local/models/telemetry.py | 6 +- pyomnilogic_local/models/util.py | 8 +- pyomnilogic_local/protocol.py | 20 +- pyomnilogic_local/util.py | 2 +- pyproject.toml | 115 ++--------- 9 files changed, 216 insertions(+), 219 deletions(-) diff --git a/poetry.lock b/poetry.lock index c52cde0..77d74dd 100644 --- a/poetry.lock +++ b/poetry.lock @@ -12,9 +12,6 @@ files = [ {file = "astroid-3.3.8.tar.gz", hash = "sha256:a88c7994f914a4ea8572fac479459f4955eeccc877be3f2d959a33273b0cf40b"}, ] -[package.dependencies] -typing-extensions = {version = ">=4.0.0", markers = "python_version < \"3.11\""} - [[package]] name = "cfgv" version = "3.4.0" @@ -112,9 +109,6 @@ files = [ {file = "coverage-7.6.10.tar.gz", hash = "sha256:7fb105327c8f8f0682e29843e2ff96af9dcbe5bab8eeb4b398c6a33a16d80a23"}, ] -[package.dependencies] -tomli = {version = "*", optional = true, markers = "python_full_version <= \"3.11.0a6\" and extra == \"toml\""} - [package.extras] toml = ["tomli"] @@ -146,22 +140,6 @@ files = [ {file = "distlib-0.3.9.tar.gz", hash = "sha256:a60f20dea646b8a33f3e7772f74dc0b2d0772d2837ee1342a00645c81edf9403"}, ] -[[package]] -name = "exceptiongroup" -version = "1.2.2" -description = "Backport of PEP 654 (exception groups)" -optional = false -python-versions = ">=3.7" -groups = ["dev"] -markers = "python_version < \"3.11\"" -files = [ - {file = "exceptiongroup-1.2.2-py3-none-any.whl", hash = "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b"}, - {file = "exceptiongroup-1.2.2.tar.gz", hash = "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc"}, -] - -[package.extras] -test = ["pytest (>=6)"] - [[package]] name = "filelock" version = "3.16.1" @@ -277,7 +255,6 @@ files = [ [package.dependencies] mypy_extensions = ">=1.0.0" -tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} typing_extensions = ">=4.6.0" [package.extras] @@ -381,7 +358,7 @@ version = "1.10.20" description = "Data validation and settings management using python type hints" optional = false python-versions = ">=3.7" -groups = ["main", "dev"] +groups = ["main"] files = [ {file = "pydantic-1.10.20-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:330d1f27b3e5a93e4b9bf5ceb6a4a4d58286b07be4ae67489413f51be300562f"}, {file = "pydantic-1.10.20-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:7254ddf29252f373c1498e3f3eb7d99b030b01d714de2319e3bf70a18859f597"}, @@ -457,15 +434,10 @@ files = [ [package.dependencies] astroid = ">=3.3.8,<=3.4.0-dev0" colorama = {version = ">=0.4.5", markers = "sys_platform == \"win32\""} -dill = [ - {version = ">=0.2", markers = "python_version < \"3.11\""}, - {version = ">=0.3.7", markers = "python_version >= \"3.12\""}, - {version = ">=0.3.6", markers = "python_version >= \"3.11\" and python_version < \"3.12\""}, -] +dill = {version = ">=0.3.7", markers = "python_version >= \"3.12\""} isort = ">=4.2.5,<5.13.0 || >5.13.0,<6" mccabe = ">=0.6,<0.8" platformdirs = ">=2.2.0" -tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} tomlkit = ">=0.10.1" [package.extras] @@ -486,11 +458,9 @@ files = [ [package.dependencies] colorama = {version = "*", markers = "sys_platform == \"win32\""} -exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""} iniconfig = "*" packaging = "*" pluggy = ">=0.12,<2.0" -tomli = {version = ">=1.0.0", markers = "python_version < \"3.11\""} [package.extras] testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] @@ -577,49 +547,6 @@ files = [ {file = "pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e"}, ] -[[package]] -name = "tomli" -version = "2.2.1" -description = "A lil' TOML parser" -optional = false -python-versions = ">=3.8" -groups = ["dev"] -markers = "python_version < \"3.11\"" -files = [ - {file = "tomli-2.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678e4fa69e4575eb77d103de3df8a895e1591b48e740211bd1067378c69e8249"}, - {file = "tomli-2.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:023aa114dd824ade0100497eb2318602af309e5a55595f76b626d6d9f3b7b0a6"}, - {file = "tomli-2.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ece47d672db52ac607a3d9599a9d48dcb2f2f735c6c2d1f34130085bb12b112a"}, - {file = "tomli-2.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6972ca9c9cc9f0acaa56a8ca1ff51e7af152a9f87fb64623e31d5c83700080ee"}, - {file = "tomli-2.2.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c954d2250168d28797dd4e3ac5cf812a406cd5a92674ee4c8f123c889786aa8e"}, - {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8dd28b3e155b80f4d54beb40a441d366adcfe740969820caf156c019fb5c7ec4"}, - {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e59e304978767a54663af13c07b3d1af22ddee3bb2fb0618ca1593e4f593a106"}, - {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:33580bccab0338d00994d7f16f4c4ec25b776af3ffaac1ed74e0b3fc95e885a8"}, - {file = "tomli-2.2.1-cp311-cp311-win32.whl", hash = "sha256:465af0e0875402f1d226519c9904f37254b3045fc5084697cefb9bdde1ff99ff"}, - {file = "tomli-2.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:2d0f2fdd22b02c6d81637a3c95f8cd77f995846af7414c5c4b8d0545afa1bc4b"}, - {file = "tomli-2.2.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4a8f6e44de52d5e6c657c9fe83b562f5f4256d8ebbfe4ff922c495620a7f6cea"}, - {file = "tomli-2.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8d57ca8095a641b8237d5b079147646153d22552f1c637fd3ba7f4b0b29167a8"}, - {file = "tomli-2.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e340144ad7ae1533cb897d406382b4b6fede8890a03738ff1683af800d54192"}, - {file = "tomli-2.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db2b95f9de79181805df90bedc5a5ab4c165e6ec3fe99f970d0e302f384ad222"}, - {file = "tomli-2.2.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:40741994320b232529c802f8bc86da4e1aa9f413db394617b9a256ae0f9a7f77"}, - {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:400e720fe168c0f8521520190686ef8ef033fb19fc493da09779e592861b78c6"}, - {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:02abe224de6ae62c19f090f68da4e27b10af2b93213d36cf44e6e1c5abd19fdd"}, - {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b82ebccc8c8a36f2094e969560a1b836758481f3dc360ce9a3277c65f374285e"}, - {file = "tomli-2.2.1-cp312-cp312-win32.whl", hash = "sha256:889f80ef92701b9dbb224e49ec87c645ce5df3fa2cc548664eb8a25e03127a98"}, - {file = "tomli-2.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:7fc04e92e1d624a4a63c76474610238576942d6b8950a2d7f908a340494e67e4"}, - {file = "tomli-2.2.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f4039b9cbc3048b2416cc57ab3bda989a6fcf9b36cf8937f01a6e731b64f80d7"}, - {file = "tomli-2.2.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:286f0ca2ffeeb5b9bd4fcc8d6c330534323ec51b2f52da063b11c502da16f30c"}, - {file = "tomli-2.2.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a92ef1a44547e894e2a17d24e7557a5e85a9e1d0048b0b5e7541f76c5032cb13"}, - {file = "tomli-2.2.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9316dc65bed1684c9a98ee68759ceaed29d229e985297003e494aa825ebb0281"}, - {file = "tomli-2.2.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e85e99945e688e32d5a35c1ff38ed0b3f41f43fad8df0bdf79f72b2ba7bc5272"}, - {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ac065718db92ca818f8d6141b5f66369833d4a80a9d74435a268c52bdfa73140"}, - {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:d920f33822747519673ee656a4b6ac33e382eca9d331c87770faa3eef562aeb2"}, - {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a198f10c4d1b1375d7687bc25294306e551bf1abfa4eace6650070a5c1ae2744"}, - {file = "tomli-2.2.1-cp313-cp313-win32.whl", hash = "sha256:d3f5614314d758649ab2ab3a62d4f2004c825922f9e370b29416484086b264ec"}, - {file = "tomli-2.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:a38aa0308e754b0e3c67e344754dff64999ff9b513e691d0e786265c93583c69"}, - {file = "tomli-2.2.1-py3-none-any.whl", hash = "sha256:cb55c73c5f4408779d0cf3eef9f762b9c9f147a77de7b258bef0a5628adc85cc"}, - {file = "tomli-2.2.1.tar.gz", hash = "sha256:cd45e1dc79c835ce60f7404ec8119f2eb06d38b1deba146f07ced3bbc44505ff"}, -] - [[package]] name = "tomlkit" version = "0.13.2" @@ -679,5 +606,5 @@ files = [ [metadata] lock-version = "2.1" -python-versions = "^3.10" -content-hash = "7f7c739bdc72823247d905d8597bb7b518c8d68fda747a440a437277917638ff" +python-versions = ">=3.12,<3.14" +content-hash = "9fb3e56ab7779dc452b5578db4e610f043fcbc973ebe5c75ea0daa0e126f5cbb" diff --git a/pyomnilogic_local/api.py b/pyomnilogic_local/api.py index 47eca9d..e8464f5 100644 --- a/pyomnilogic_local/api.py +++ b/pyomnilogic_local/api.py @@ -1,9 +1,10 @@ +# pylint: disable=too-many-positional-arguments from __future__ import annotations import asyncio import logging -from typing import Literal, overload import xml.etree.ElementTree as ET +from typing import Literal, overload from .models.filter_diagnostics import FilterDiagnostics from .models.mspconfig import MSPConfig @@ -30,14 +31,27 @@ def __init__(self, controller_ip: str, controller_port: int, response_timeout: f self._protocol_factory = OmniLogicProtocol @overload - async def async_send_message(self, message_type: MessageType, message: str | None, need_response: Literal[True]) -> str: - ... + async def async_send_message( + self, + message_type: MessageType, + message: str | None, + need_response: Literal[True], + ) -> str: ... @overload - async def async_send_message(self, message_type: MessageType, message: str | None, need_response: Literal[False]) -> None: - ... + async def async_send_message( + self, + message_type: MessageType, + message: str | None, + need_response: Literal[False], + ) -> None: ... - async def async_send_message(self, message_type: MessageType, message: str | None, need_response: bool = False) -> str | None: + async def async_send_message( + self, + message_type: MessageType, + message: str | None, + need_response: bool = False, + ) -> str | None: """Send a message via the Hayward Omni UDP protocol along with properly handling timeouts and responses. Args: @@ -166,9 +180,22 @@ async def async_set_heater(self, pool_id: int, equipment_id: int, temperature: i parameters_element = ET.SubElement(body_element, "Parameters") parameter = ET.SubElement(parameters_element, "Parameter", name="poolId", dataType="int") parameter.text = str(pool_id) - parameter = ET.SubElement(parameters_element, "Parameter", name="HeaterID", dataType="int", alias="EquipmentID") + parameter = ET.SubElement( + parameters_element, + "Parameter", + name="HeaterID", + dataType="int", + alias="EquipmentID", + ) parameter.text = str(equipment_id) - parameter = ET.SubElement(parameters_element, "Parameter", name="Temp", dataType="int", unit=unit, alias="Data") + parameter = ET.SubElement( + parameters_element, + "Parameter", + name="Temp", + dataType="int", + unit=unit, + alias="Data", + ) parameter.text = str(temperature) req_body = ET.tostring(body_element, xml_declaration=True, encoding="unicode") @@ -195,9 +222,22 @@ async def async_set_solar_heater(self, pool_id: int, equipment_id: int, temperat parameters_element = ET.SubElement(body_element, "Parameters") parameter = ET.SubElement(parameters_element, "Parameter", name="poolId", dataType="int") parameter.text = str(pool_id) - parameter = ET.SubElement(parameters_element, "Parameter", name="HeaterID", dataType="int", alias="EquipmentID") + parameter = ET.SubElement( + parameters_element, + "Parameter", + name="HeaterID", + dataType="int", + alias="EquipmentID", + ) parameter.text = str(equipment_id) - parameter = ET.SubElement(parameters_element, "Parameter", name="Temp", dataType="int", unit=unit, alias="Data") + parameter = ET.SubElement( + parameters_element, + "Parameter", + name="Temp", + dataType="int", + unit=unit, + alias="Data", + ) parameter.text = str(temperature) req_body = ET.tostring(body_element, xml_declaration=True, encoding="unicode") @@ -223,7 +263,13 @@ async def async_set_heater_mode(self, pool_id: int, equipment_id: int, mode: Hea parameters_element = ET.SubElement(body_element, "Parameters") parameter = ET.SubElement(parameters_element, "Parameter", name="poolId", dataType="int") parameter.text = str(pool_id) - parameter = ET.SubElement(parameters_element, "Parameter", name="HeaterID", dataType="int", alias="EquipmentID") + parameter = ET.SubElement( + parameters_element, + "Parameter", + name="HeaterID", + dataType="int", + alias="EquipmentID", + ) parameter.text = str(equipment_id) parameter = ET.SubElement(parameters_element, "Parameter", name="Mode", dataType="int", alias="Data") parameter.text = str(mode.value) @@ -251,9 +297,21 @@ async def async_set_heater_enable(self, pool_id: int, equipment_id: int, enabled parameters_element = ET.SubElement(body_element, "Parameters") parameter = ET.SubElement(parameters_element, "Parameter", name="poolId", dataType="int") parameter.text = str(pool_id) - parameter = ET.SubElement(parameters_element, "Parameter", name="HeaterID", dataType="int", alias="EquipmentID") + parameter = ET.SubElement( + parameters_element, + "Parameter", + name="HeaterID", + dataType="int", + alias="EquipmentID", + ) parameter.text = str(equipment_id) - parameter = ET.SubElement(parameters_element, "Parameter", name="Enabled", dataType="bool", alias="Data") + parameter = ET.SubElement( + parameters_element, + "Parameter", + name="Enabled", + dataType="bool", + alias="Data", + ) parameter.text = str(int(enabled)) req_body = ET.tostring(body_element, xml_declaration=True, encoding="unicode") @@ -336,10 +394,23 @@ async def async_set_filter_speed(self, pool_id: int, equipment_id: int, speed: i parameters_element = ET.SubElement(body_element, "Parameters") parameter = ET.SubElement(parameters_element, "Parameter", name="poolId", dataType="int") parameter.text = str(pool_id) - parameter = ET.SubElement(parameters_element, "Parameter", name="FilterID", dataType="int", alias="equipment_id") + parameter = ET.SubElement( + parameters_element, + "Parameter", + name="FilterID", + dataType="int", + alias="equipment_id", + ) parameter.text = str(equipment_id) # NOTE: Despite the API calling it RPM here, the speed value is a percentage from 1-100 - parameter = ET.SubElement(parameters_element, "Parameter", name="Speed", dataType="int", unit="RPM", alias="Data") + parameter = ET.SubElement( + parameters_element, + "Parameter", + name="Speed", + dataType="int", + unit="RPM", + alias="Data", + ) parameter.text = str(speed) req_body = ET.tostring(body_element, xml_declaration=True, encoding="unicode") @@ -387,7 +458,13 @@ async def async_set_light_show( parameters_element = ET.SubElement(body_element, "Parameters") parameter = ET.SubElement(parameters_element, "Parameter", name="poolId", dataType="int") parameter.text = str(pool_id) - parameter = ET.SubElement(parameters_element, "Parameter", name="LightID", dataType="int", alias="equipment_id") + parameter = ET.SubElement( + parameters_element, + "Parameter", + name="LightID", + dataType="int", + alias="equipment_id", + ) parameter.text = str(equipment_id) parameter = ET.SubElement(parameters_element, "Parameter", name="Show", dataType="byte") parameter.text = str(show.value) @@ -424,7 +501,13 @@ async def async_set_chlorinator_enable(self, pool_id: int, enabled: int | bool) parameters_element = ET.SubElement(body_element, "Parameters") parameter = ET.SubElement(parameters_element, "Parameter", name="poolId", dataType="int") parameter.text = str(pool_id) - parameter = ET.SubElement(parameters_element, "Parameter", name="Enabled", dataType="bool", alias="Data") + parameter = ET.SubElement( + parameters_element, + "Parameter", + name="Enabled", + dataType="bool", + alias="Data", + ) parameter.text = str(int(enabled)) req_body = ET.tostring(body_element, xml_declaration=True, encoding="unicode") @@ -451,21 +534,71 @@ async def async_set_chlorinator_params( parameters_element = ET.SubElement(body_element, "Parameters") parameter = ET.SubElement(parameters_element, "Parameter", name="poolId", dataType="int") parameter.text = str(pool_id) - parameter = ET.SubElement(parameters_element, "Parameter", name="ChlorID", dataType="int", alias="EquipmentID") + parameter = ET.SubElement( + parameters_element, + "Parameter", + name="ChlorID", + dataType="int", + alias="EquipmentID", + ) parameter.text = str(equipment_id) - parameter = ET.SubElement(parameters_element, "Parameter", name="CfgState", dataType="byte", alias="Data1") + parameter = ET.SubElement( + parameters_element, + "Parameter", + name="CfgState", + dataType="byte", + alias="Data1", + ) parameter.text = str(cfg_state) - parameter = ET.SubElement(parameters_element, "Parameter", name="OpMode", dataType="byte", alias="Data2") + parameter = ET.SubElement( + parameters_element, + "Parameter", + name="OpMode", + dataType="byte", + alias="Data2", + ) parameter.text = str(op_mode) - parameter = ET.SubElement(parameters_element, "Parameter", name="BOWType", dataType="byte", alias="Data3") + parameter = ET.SubElement( + parameters_element, + "Parameter", + name="BOWType", + dataType="byte", + alias="Data3", + ) parameter.text = str(bow_type) - parameter = ET.SubElement(parameters_element, "Parameter", name="CellType", dataType="byte", alias="Data4") + parameter = ET.SubElement( + parameters_element, + "Parameter", + name="CellType", + dataType="byte", + alias="Data4", + ) parameter.text = str(cell_type) - parameter = ET.SubElement(parameters_element, "Parameter", name="TimedPercent", dataType="byte", alias="Data5") + parameter = ET.SubElement( + parameters_element, + "Parameter", + name="TimedPercent", + dataType="byte", + alias="Data5", + ) parameter.text = str(timed_percent) - parameter = ET.SubElement(parameters_element, "Parameter", name="SCTimeout", dataType="byte", unit="hour", alias="Data6") + parameter = ET.SubElement( + parameters_element, + "Parameter", + name="SCTimeout", + dataType="byte", + unit="hour", + alias="Data6", + ) parameter.text = str(sc_timeout) - parameter = ET.SubElement(parameters_element, "Parameter", name="ORPTimout", dataType="byte", unit="hour", alias="Data7") + parameter = ET.SubElement( + parameters_element, + "Parameter", + name="ORPTimout", + dataType="byte", + unit="hour", + alias="Data7", + ) parameter.text = str(orp_timeout) req_body = ET.tostring(body_element, xml_declaration=True, encoding="unicode") @@ -481,7 +614,13 @@ async def async_set_chlorinator_superchlorinate(self, pool_id: int, equipment_id parameters_element = ET.SubElement(body_element, "Parameters") parameter = ET.SubElement(parameters_element, "Parameter", name="poolId", dataType="int") parameter.text = str(pool_id) - parameter = ET.SubElement(parameters_element, "Parameter", name="ChlorID", dataType="int", alias="EquipmentID") + parameter = ET.SubElement( + parameters_element, + "Parameter", + name="ChlorID", + dataType="int", + alias="EquipmentID", + ) parameter.text = str(equipment_id) parameter = ET.SubElement(parameters_element, "Parameter", name="IsOn", dataType="byte", alias="Data1") parameter.text = str(int(enabled)) diff --git a/pyomnilogic_local/models/filter_diagnostics.py b/pyomnilogic_local/models/filter_diagnostics.py index 6bd7c79..4920858 100644 --- a/pyomnilogic_local/models/filter_diagnostics.py +++ b/pyomnilogic_local/models/filter_diagnostics.py @@ -23,6 +23,7 @@ class Config: orm_mode = True def get_param_by_name(self, name: str) -> int: + # pylint: disable=not-an-iterable return [param.value for param in self.parameters if param.name == name][0] @staticmethod diff --git a/pyomnilogic_local/models/mspconfig.py b/pyomnilogic_local/models/mspconfig.py index 640071f..70d13a3 100644 --- a/pyomnilogic_local/models/mspconfig.py +++ b/pyomnilogic_local/models/mspconfig.py @@ -188,7 +188,16 @@ def __init__(self, **data: Any) -> None: class MSPBoW(OmniBase): - _sub_devices = {"filter", "relay", "heater", "sensor", "colorlogic_light", "pump", "chlorinator", "csad"} + _sub_devices = { + "filter", + "relay", + "heater", + "sensor", + "colorlogic_light", + "pump", + "chlorinator", + "csad", + } omni_type: OmniType = OmniType.BOW type: BodyOfWaterType | str = Field(alias="Type") diff --git a/pyomnilogic_local/models/telemetry.py b/pyomnilogic_local/models/telemetry.py index a0bafed..fe5c8f5 100644 --- a/pyomnilogic_local/models/telemetry.py +++ b/pyomnilogic_local/models/telemetry.py @@ -200,12 +200,10 @@ def load_xml(xml: str) -> Telemetry: TypeVar("VT", SupportsInt, Any) @overload - def xml_postprocessor(path: Any, key: Any, value: SupportsInt) -> tuple[Any, SupportsInt]: - ... + def xml_postprocessor(path: Any, key: Any, value: SupportsInt) -> tuple[Any, SupportsInt]: ... @overload - def xml_postprocessor(path: Any, key: Any, value: Any) -> tuple[Any, Any]: - ... + def xml_postprocessor(path: Any, key: Any, value: Any) -> tuple[Any, Any]: ... def xml_postprocessor(path: Any, key: Any, value: SupportsInt | Any) -> tuple[Any, SupportsInt | Any]: """Post process XML to attempt to convert values to int. diff --git a/pyomnilogic_local/models/util.py b/pyomnilogic_local/models/util.py index 6b786d5..99a32ac 100644 --- a/pyomnilogic_local/models/util.py +++ b/pyomnilogic_local/models/util.py @@ -1,5 +1,5 @@ -from collections.abc import Awaitable, Callable import logging +from collections.abc import Awaitable, Callable from typing import Any, Literal, TypeVar, cast, overload from pydantic.v1.utils import GetterDict @@ -29,12 +29,10 @@ def inner(func: F, *args: Any, **kwargs: Any) -> F: """Wrap an API function that returns XML and parse it into a Pydantic model""" @overload - async def wrapper(*args: Any, raw: Literal[True], **kwargs: Any) -> str: - ... + async def wrapper(*args: Any, raw: Literal[True], **kwargs: Any) -> str: ... @overload - async def wrapper(*args: Any, raw: Literal[False], **kwargs: Any) -> TPydanticTypes: - ... + async def wrapper(*args: Any, raw: Literal[False], **kwargs: Any) -> TPydanticTypes: ... async def wrapper(*args: Any, raw: bool = False, **kwargs: Any) -> TPydanticTypes | str: resp_body = await func(*args, **kwargs) diff --git a/pyomnilogic_local/protocol.py b/pyomnilogic_local/protocol.py index a87b9e1..f9ee508 100644 --- a/pyomnilogic_local/protocol.py +++ b/pyomnilogic_local/protocol.py @@ -3,9 +3,9 @@ import random import struct import time -from typing import Any, cast import xml.etree.ElementTree as ET import zlib +from typing import Any, cast from typing_extensions import Self @@ -28,7 +28,13 @@ class OmniLogicMessage: compressed: bool = False reserved_2: int = 0 - def __init__(self, msg_id: int, msg_type: MessageType, payload: str | None = None, version: str = "1.19") -> None: + def __init__( + self, + msg_id: int, + msg_type: MessageType, + payload: str | None = None, + version: str = "1.19", + ) -> None: self.id = msg_id self.type = msg_type # If we are speaking the XML API, it seems like we need client_type 0, otherwise we need client_type 1 @@ -117,7 +123,10 @@ async def _wait_for_ack(self, ack_id: int) -> None: # Us > Omni: MessageType.REQUEST_CONFIGURATION # Omni > Us: MessageType.ACK # Omni > Us: MessageType.MSP_LEADMESSAGE <--- Sent immediately after an ACK - if message.type in {MessageType.MSP_LEADMESSAGE, MessageType.MSP_TELEMETRY_UPDATE}: + if message.type in { + MessageType.MSP_LEADMESSAGE, + MessageType.MSP_TELEMETRY_UPDATE, + }: _LOGGER.debug("Omni has sent a new message, continuing on with the communication") await self.data_queue.put(message) break @@ -192,7 +201,10 @@ async def _receive_file(self) -> str: while len(data_fragments) < leadmsg.msg_block_count: # We need to wait long enough for the Omni to get through all of it's retries before we bail out. try: - resp = await asyncio.wait_for(self.data_queue.get(), self._omni_retransmit_time * self._omni_retransmit_count) + resp = await asyncio.wait_for( + self.data_queue.get(), + self._omni_retransmit_time * self._omni_retransmit_count, + ) except TimeoutError as exc: raise OmniTimeoutException from exc diff --git a/pyomnilogic_local/util.py b/pyomnilogic_local/util.py index 6c0246d..b2b0cfb 100644 --- a/pyomnilogic_local/util.py +++ b/pyomnilogic_local/util.py @@ -1,5 +1,5 @@ -from enum import Enum import sys +from enum import Enum if sys.version_info >= (3, 11): from typing import Self diff --git a/pyproject.toml b/pyproject.toml index d6d53a8..ec630bc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,43 +1,29 @@ -[tool.poetry] +[project] name = "python-omnilogic-local" version = "0.14.6" description = "A library for local control of Hayward OmniHub/OmniLogic pool controllers using their local API" -authors = ["cryptk ", "djtimca", "garionphx"] -license = "Apache-2.0" +authors = [ + {name = "Chris Jowett",email = "421501+cryptk@users.noreply.github.com"} +] +license = {text = "Apache-2.0"} readme = "README.md" -repository = "https://github.com/cryptk/python-omnilogic-local" -classifiers = [ - "Development Status :: 3 - Alpha", - "Intended Audience :: Developers", - "Natural Language :: English", - "Operating System :: OS Independent", - "Topic :: Software Development :: Libraries", +requires-python = ">=3.12,<3.14" +dependencies = [ + "pydantic (>=1.10.17)", + "xmltodict (>=0.13.0,<0.14.0)" ] -packages = [{include = "pyomnilogic_local"}] - -[tool.poetry.scripts] -omnilogic = "pyomnilogic_local.cli:main" -[tool.poetry.dependencies] -python = "^3.10" -pydantic = ">=1.10.17" -xmltodict = "^0.13.0" +[tool.poetry] [tool.poetry.group.dev.dependencies] pre-commit = "^3.0.0" mypy = "^1.2.0" pylint = "^3.2.3" -pydantic = "^1.10.7" pytest = "^7.3.1" pytest-cov = "^4.1.0" -[tool.pytest.ini_options] -addopts = [ - "--import-mode=importlib", -] - [build-system] -requires = ["poetry-core"] +requires = ["poetry-core>=2.0.0,<3.0.0"] build-backend = "poetry.core.masonry.api" [tool.black] @@ -46,52 +32,9 @@ line-length=140 [tool.isort] # https://github.com/PyCQA/isort/wiki/isort-Settings profile = "black" -# will group `import x` and `from x import` of the same module. -force_sort_within_sections = true -known_first_party = [ - "homeassistant", - "tests", -] -forced_separate = [ - "tests", -] -combine_as_imports = true - -[tool.mypy] -python_version = "3.10" -plugins = "pydantic.mypy" -follow_imports = "silent" -strict = true -ignore_missing_imports = true -disallow_subclassing_any = false -warn_return_any = false -# local_partial_types = true -# strict_equality = true -# no_implicit_optional = true -# warn_incomplete_stub = true -# warn_redundant_casts = true -# warn_unused_configs = true -# warn_unused_ignores = true -# enable_error_code = "ignore-without-code, redundant-self, truthy-iterable" -# disable_error_code = "annotation-unchecked" -# strict_concatenate = false -# check_untyped_defs = true -# disallow_incomplete_defs = true -# disallow_untyped_calls = true -# disallow_untyped_decorators = true -# disallow_untyped_defs = true -# warn_unreachable = true -# no_implicit_reexport = true -# disallow_any_generics = true - -[tool.pydantic-mypy] -init_forbid_extra = true -init_typed = true -warn_required_dynamic_aliases = true -warn_untyped_fields = true [tool.pylint.MAIN] -py-version = "3.11" +py-version = "3.13" ignore = [ "tests", ] @@ -102,31 +45,6 @@ load-plugins = [ "pylint.extensions.code_style", "pylint.extensions.typing", ] -persistent = false -extension-pkg-allow-list = [ - "pydantic", -] -fail-on = [ - "I", -] - -[tool.pylint.BASIC] -class-const-naming-style = "any" -good-names = [ - "_", - "ev", - "ex", - "fp", - "i", - "id", - "j", - "k", - "Run", - "ip", -] - -[tool.pylint.CODE_STYLE] -max-line-length-suggestions = 72 [tool.pylint."FORMAT"] expected-line-ending-format = "LF" @@ -175,25 +93,20 @@ disable = [ "wrong-import-order", "wrong-import-position", "consider-using-f-string", - "consider-using-namedtuple-or-dataclass", - "consider-using-assignment-expr", # The below are only here for now, we should fully document once the codebase stops fluctuating so much "missing-class-docstring", "missing-function-docstring", "missing-module-docstring", ] enable = [ - "useless-suppression", # temporarily every now and then to clean them up + "useless-suppression", "use-symbolic-message-instead", ] -[tool.pylint.REPORTS] -score = false - [tool.ruff] line-length = 140 [tool.semantic_release] branch = "main" -version_toml = "pyproject.toml:tool.poetry.version" +version_toml = "pyproject.toml:project.version" build_command = "pip install poetry && poetry build"