"""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