326 lines
8.9 KiB
Python
326 lines
8.9 KiB
Python
"""Support for ISY994 sensors."""
|
|
import logging
|
|
from typing import Callable
|
|
|
|
from homeassistant.components.sensor import DOMAIN
|
|
from homeassistant.const import POWER_WATT, TEMP_CELSIUS, TEMP_FAHRENHEIT, UNIT_UV_INDEX
|
|
from homeassistant.helpers.typing import ConfigType
|
|
|
|
from . import ISY994_NODES, ISY994_WEATHER, ISYDevice
|
|
|
|
_LOGGER = logging.getLogger(__name__)
|
|
|
|
UOM_FRIENDLY_NAME = {
|
|
"1": "amp",
|
|
"3": "btu/h",
|
|
"4": TEMP_CELSIUS,
|
|
"5": "cm",
|
|
"6": "ft³",
|
|
"7": "ft³/min",
|
|
"8": "m³",
|
|
"9": "day",
|
|
"10": "days",
|
|
"12": "dB",
|
|
"13": "dB A",
|
|
"14": "°",
|
|
"16": "macroseismic",
|
|
"17": TEMP_FAHRENHEIT,
|
|
"18": "ft",
|
|
"19": "hour",
|
|
"20": "hours",
|
|
"21": "abs. humidity (%)",
|
|
"22": "rel. humidity (%)",
|
|
"23": "inHg",
|
|
"24": "in/hr",
|
|
"25": "index",
|
|
"26": "K",
|
|
"27": "keyword",
|
|
"28": "kg",
|
|
"29": "kV",
|
|
"30": "kW",
|
|
"31": "kPa",
|
|
"32": "KPH",
|
|
"33": "kWH",
|
|
"34": "liedu",
|
|
"35": "l",
|
|
"36": "lx",
|
|
"37": "mercalli",
|
|
"38": "m",
|
|
"39": "m³/hr",
|
|
"40": "m/s",
|
|
"41": "mA",
|
|
"42": "ms",
|
|
"43": "mV",
|
|
"44": "min",
|
|
"45": "min",
|
|
"46": "mm/hr",
|
|
"47": "month",
|
|
"48": "MPH",
|
|
"49": "m/s",
|
|
"50": "ohm",
|
|
"51": "%",
|
|
"52": "lb",
|
|
"53": "power factor",
|
|
"54": "ppm",
|
|
"55": "pulse count",
|
|
"57": "s",
|
|
"58": "s",
|
|
"59": "seimens/m",
|
|
"60": "body wave magnitude scale",
|
|
"61": "Ricter scale",
|
|
"62": "moment magnitude scale",
|
|
"63": "surface wave magnitude scale",
|
|
"64": "shindo",
|
|
"65": "SML",
|
|
"69": "gal",
|
|
"71": UNIT_UV_INDEX,
|
|
"72": "V",
|
|
"73": POWER_WATT,
|
|
"74": "W/m²",
|
|
"75": "weekday",
|
|
"76": "Wind Direction (°)",
|
|
"77": "year",
|
|
"82": "mm",
|
|
"83": "km",
|
|
"85": "ohm",
|
|
"86": "kOhm",
|
|
"87": "m³/m³",
|
|
"88": "Water activity",
|
|
"89": "RPM",
|
|
"90": "Hz",
|
|
"91": "° (Relative to North)",
|
|
"92": "° (Relative to South)",
|
|
}
|
|
|
|
UOM_TO_STATES = {
|
|
"11": {"0": "unlocked", "100": "locked", "102": "jammed"},
|
|
"15": {
|
|
"1": "master code changed",
|
|
"2": "tamper code entry limit",
|
|
"3": "escutcheon removed",
|
|
"4": "key/manually locked",
|
|
"5": "locked by touch",
|
|
"6": "key/manually unlocked",
|
|
"7": "remote locking jammed bolt",
|
|
"8": "remotely locked",
|
|
"9": "remotely unlocked",
|
|
"10": "deadbolt jammed",
|
|
"11": "battery too low to operate",
|
|
"12": "critical low battery",
|
|
"13": "low battery",
|
|
"14": "automatically locked",
|
|
"15": "automatic locking jammed bolt",
|
|
"16": "remotely power cycled",
|
|
"17": "lock handling complete",
|
|
"19": "user deleted",
|
|
"20": "user added",
|
|
"21": "duplicate pin",
|
|
"22": "jammed bolt by locking with keypad",
|
|
"23": "locked by keypad",
|
|
"24": "unlocked by keypad",
|
|
"25": "keypad attempt outside schedule",
|
|
"26": "hardware failure",
|
|
"27": "factory reset",
|
|
},
|
|
"66": {
|
|
"0": "idle",
|
|
"1": "heating",
|
|
"2": "cooling",
|
|
"3": "fan only",
|
|
"4": "pending heat",
|
|
"5": "pending cool",
|
|
"6": "vent",
|
|
"7": "aux heat",
|
|
"8": "2nd stage heating",
|
|
"9": "2nd stage cooling",
|
|
"10": "2nd stage aux heat",
|
|
"11": "3rd stage aux heat",
|
|
},
|
|
"67": {
|
|
"0": "off",
|
|
"1": "heat",
|
|
"2": "cool",
|
|
"3": "auto",
|
|
"4": "aux/emergency heat",
|
|
"5": "resume",
|
|
"6": "fan only",
|
|
"7": "furnace",
|
|
"8": "dry air",
|
|
"9": "moist air",
|
|
"10": "auto changeover",
|
|
"11": "energy save heat",
|
|
"12": "energy save cool",
|
|
"13": "away",
|
|
},
|
|
"68": {
|
|
"0": "auto",
|
|
"1": "on",
|
|
"2": "auto high",
|
|
"3": "high",
|
|
"4": "auto medium",
|
|
"5": "medium",
|
|
"6": "circulation",
|
|
"7": "humidity circulation",
|
|
},
|
|
"93": {
|
|
"1": "power applied",
|
|
"2": "ac mains disconnected",
|
|
"3": "ac mains reconnected",
|
|
"4": "surge detection",
|
|
"5": "volt drop or drift",
|
|
"6": "over current detected",
|
|
"7": "over voltage detected",
|
|
"8": "over load detected",
|
|
"9": "load error",
|
|
"10": "replace battery soon",
|
|
"11": "replace battery now",
|
|
"12": "battery is charging",
|
|
"13": "battery is fully charged",
|
|
"14": "charge battery soon",
|
|
"15": "charge battery now",
|
|
},
|
|
"94": {
|
|
"1": "program started",
|
|
"2": "program in progress",
|
|
"3": "program completed",
|
|
"4": "replace main filter",
|
|
"5": "failure to set target temperature",
|
|
"6": "supplying water",
|
|
"7": "water supply failure",
|
|
"8": "boiling",
|
|
"9": "boiling failure",
|
|
"10": "washing",
|
|
"11": "washing failure",
|
|
"12": "rinsing",
|
|
"13": "rinsing failure",
|
|
"14": "draining",
|
|
"15": "draining failure",
|
|
"16": "spinning",
|
|
"17": "spinning failure",
|
|
"18": "drying",
|
|
"19": "drying failure",
|
|
"20": "fan failure",
|
|
"21": "compressor failure",
|
|
},
|
|
"95": {
|
|
"1": "leaving bed",
|
|
"2": "sitting on bed",
|
|
"3": "lying on bed",
|
|
"4": "posture changed",
|
|
"5": "sitting on edge of bed",
|
|
},
|
|
"96": {
|
|
"1": "clean",
|
|
"2": "slightly polluted",
|
|
"3": "moderately polluted",
|
|
"4": "highly polluted",
|
|
},
|
|
"97": {
|
|
"0": "closed",
|
|
"100": "open",
|
|
"102": "stopped",
|
|
"103": "closing",
|
|
"104": "opening",
|
|
},
|
|
}
|
|
|
|
|
|
def setup_platform(
|
|
hass, config: ConfigType, add_entities: Callable[[list], None], discovery_info=None
|
|
):
|
|
"""Set up the ISY994 sensor platform."""
|
|
devices = []
|
|
|
|
for node in hass.data[ISY994_NODES][DOMAIN]:
|
|
_LOGGER.debug("Loading %s", node.name)
|
|
devices.append(ISYSensorDevice(node))
|
|
|
|
for node in hass.data[ISY994_WEATHER]:
|
|
devices.append(ISYWeatherDevice(node))
|
|
|
|
add_entities(devices)
|
|
|
|
|
|
class ISYSensorDevice(ISYDevice):
|
|
"""Representation of an ISY994 sensor device."""
|
|
|
|
@property
|
|
def raw_unit_of_measurement(self) -> str:
|
|
"""Get the raw unit of measurement for the ISY994 sensor device."""
|
|
if len(self._node.uom) == 1:
|
|
if self._node.uom[0] in UOM_FRIENDLY_NAME:
|
|
friendly_name = UOM_FRIENDLY_NAME.get(self._node.uom[0])
|
|
if friendly_name in (TEMP_CELSIUS, TEMP_FAHRENHEIT):
|
|
friendly_name = self.hass.config.units.temperature_unit
|
|
return friendly_name
|
|
return self._node.uom[0]
|
|
return None
|
|
|
|
@property
|
|
def state(self) -> str:
|
|
"""Get the state of the ISY994 sensor device."""
|
|
if self.is_unknown():
|
|
return None
|
|
|
|
if len(self._node.uom) == 1:
|
|
if self._node.uom[0] in UOM_TO_STATES:
|
|
states = UOM_TO_STATES.get(self._node.uom[0])
|
|
if self.value in states:
|
|
return states.get(self.value)
|
|
elif self._node.prec and self._node.prec != [0]:
|
|
str_val = str(self.value)
|
|
int_prec = int(self._node.prec)
|
|
decimal_part = str_val[-int_prec:]
|
|
whole_part = str_val[: len(str_val) - int_prec]
|
|
val = float(f"{whole_part}.{decimal_part}")
|
|
raw_units = self.raw_unit_of_measurement
|
|
if raw_units in (TEMP_CELSIUS, TEMP_FAHRENHEIT):
|
|
val = self.hass.config.units.temperature(val, raw_units)
|
|
|
|
return str(val)
|
|
else:
|
|
return self.value
|
|
|
|
return None
|
|
|
|
@property
|
|
def unit_of_measurement(self) -> str:
|
|
"""Get the unit of measurement for the ISY994 sensor device."""
|
|
raw_units = self.raw_unit_of_measurement
|
|
if raw_units in (TEMP_FAHRENHEIT, TEMP_CELSIUS):
|
|
return self.hass.config.units.temperature_unit
|
|
return raw_units
|
|
|
|
|
|
class ISYWeatherDevice(ISYDevice):
|
|
"""Representation of an ISY994 weather device."""
|
|
|
|
@property
|
|
def raw_units(self) -> str:
|
|
"""Return the raw unit of measurement."""
|
|
if self._node.uom == "F":
|
|
return TEMP_FAHRENHEIT
|
|
if self._node.uom == "C":
|
|
return TEMP_CELSIUS
|
|
return self._node.uom
|
|
|
|
@property
|
|
def state(self) -> object:
|
|
"""Return the value of the node."""
|
|
# pylint: disable=protected-access
|
|
val = self._node.status._val
|
|
raw_units = self._node.uom
|
|
|
|
if raw_units in [TEMP_CELSIUS, TEMP_FAHRENHEIT]:
|
|
return self.hass.config.units.temperature(val, raw_units)
|
|
return val
|
|
|
|
@property
|
|
def unit_of_measurement(self) -> str:
|
|
"""Return the unit of measurement for the node."""
|
|
raw_units = self.raw_units
|
|
|
|
if raw_units in [TEMP_CELSIUS, TEMP_FAHRENHEIT]:
|
|
return self.hass.config.units.temperature_unit
|
|
return raw_units
|