Source code for pyisyox.helpers

"""Helper functions for the PyISYoX Module."""

from __future__ import annotations

import datetime
from typing import cast

from pyisyox.constants import (
    EMPTY_TIME,
    ISY_VALUE_UNKNOWN,
    MILITARY_TIME,
    STANDARD_TIME,
    UOM_DOUBLE_TEMP,
    UOM_ISYV4_DEGREES,
    XML_STRPTIME,
    XML_STRPTIME_YY,
)
from pyisyox.logging import _LOGGER


[docs] def parse_isy_datetime(dt_str: str | None) -> datetime.datetime: """Parse an ISY datetime string, returning ``EMPTY_TIME`` on failure. Handles the four documented ISY datetime formats plus an ISO 8601 fallback. Replaces the prior dependency on ``python-dateutil``. """ if not dt_str or not isinstance(dt_str, str): return EMPTY_TIME for fmt in (MILITARY_TIME, STANDARD_TIME, XML_STRPTIME, XML_STRPTIME_YY): try: return datetime.datetime.strptime(dt_str, fmt) except ValueError: continue try: return datetime.datetime.fromisoformat(dt_str) except ValueError: _LOGGER.debug("Could not parse ISY datetime: %s", dt_str) return EMPTY_TIME
[docs] def convert_isy_raw_value( value: float, uom: str | None, precision: int | str, fallback_precision: int | None = None, ) -> float | int: """Fix ISY Reported Values. ISY provides float values as an integer and precision component. Correct by shifting the decimal place left by the value of precision. (e.g. value=2345, precision=2 → 23.45; wire keys it as "prec") Insteon Thermostats report temperature in 0.5-deg precision as an int by sending a value of 2 times the Temp. Correct by dividing by 2 here. Args: value (int | float): The value to convert. uom (str, optional): The ISY Unit of Measure code. Default is None. precision (int | str): The precision (decimal places) to convert the value to. fallback_precision (int, optional): The fallback precision to use with normal rounding. Default is None. Returns: float | int: The converted value """ if value is None or value == ISY_VALUE_UNKNOWN: return ISY_VALUE_UNKNOWN if uom in (UOM_DOUBLE_TEMP, UOM_ISYV4_DEGREES): return round(float(value) / 2.0, 1) if precision not in ("0", 0): return cast(float, round(float(value) / 10 ** int(precision), int(precision))) if fallback_precision: return round(float(value), fallback_precision) return value