core/homeassistant/components/sensor/isy994.py

359 lines
9.8 KiB
Python

"""
Support for ISY994 sensors.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/sensor.isy994/
"""
import logging
from typing import Callable # noqa
import homeassistant.components.isy994 as isy
from homeassistant.const import (
TEMP_CELSIUS, TEMP_FAHRENHEIT, STATE_OFF, STATE_ON)
from homeassistant.helpers.typing import ConfigType
_LOGGER = logging.getLogger(__name__)
UOM_FRIENDLY_NAME = {
'1': 'amp',
'3': 'btu/h',
'4': TEMP_CELSIUS,
'5': 'cm',
'6': 'ft³',
'7': 'ft³/min',
'8': '',
'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': 'lux',
'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': 'UV index',
'72': 'V',
'73': 'W',
'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'
}
}
BINARY_UOM = ['2', '78']
# pylint: disable=unused-argument
def setup_platform(hass, config: ConfigType,
add_devices: Callable[[list], None], discovery_info=None):
"""Set up the ISY994 sensor platform."""
if isy.ISY is None or not isy.ISY.connected:
_LOGGER.error("A connection has not been made to the ISY controller")
return False
devices = []
for node in isy.SENSOR_NODES:
if (not node.uom or node.uom[0] not in BINARY_UOM) and \
STATE_OFF not in node.uom and STATE_ON not in node.uom:
_LOGGER.debug("Loading %s", node.name)
devices.append(ISYSensorDevice(node))
for node in isy.WEATHER_NODES:
devices.append(ISYWeatherDevice(node))
add_devices(devices)
class ISYSensorDevice(isy.ISYDevice):
"""Representation of an ISY994 sensor device."""
def __init__(self, node) -> None:
"""Initialize the ISY994 sensor device."""
isy.ISYDevice.__init__(self, node)
@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 == TEMP_CELSIUS or \
friendly_name == TEMP_FAHRENHEIT:
friendly_name = self.hass.config.units.temperature_unit
return friendly_name
else:
return self._node.uom[0]
else:
return None
@property
def state(self) -> str:
"""Get the state of the ISY994 sensor device."""
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('{}.{}'.format(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
else:
return raw_units
class ISYWeatherDevice(isy.ISYDevice):
"""Representation of an ISY994 weather device."""
_domain = 'sensor'
def __init__(self, node) -> None:
"""Initialize the ISY994 weather device."""
isy.ISYDevice.__init__(self, node)
@property
def unique_id(self) -> str:
"""Return the unique identifier for the node."""
return self._node.name
@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