text: """
  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': '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': '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
          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
  