Code conformance and sensor value clean-up on ISY994 (#35514)
* Consolidate value conversion functions * Update to sensor * Fix property name * Revise sensors and state reporting per code standards * Update uom function and revert to property
This commit is contained in:
parent
2f73361381
commit
b1d59679e5
11 changed files with 123 additions and 170 deletions
|
@ -24,7 +24,6 @@ from homeassistant.components.binary_sensor import (
|
|||
BinarySensorEntity,
|
||||
)
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import STATE_OFF, STATE_ON, STATE_UNKNOWN
|
||||
from homeassistant.core import callback
|
||||
from homeassistant.helpers.event import async_track_point_in_utc_time
|
||||
from homeassistant.helpers.typing import HomeAssistantType
|
||||
|
@ -136,7 +135,7 @@ async def async_setup_entry(
|
|||
# the initial state is forced "OFF"/"NORMAL" if the
|
||||
# parent device has a valid state. This is corrected
|
||||
# upon connection to the ISY event stream if subnode has a valid state.
|
||||
initial_state = None if parent_device.state == STATE_UNKNOWN else False
|
||||
initial_state = None if parent_device.state is None else False
|
||||
if subnode_id == SUBNODE_DUSK_DAWN:
|
||||
# Subnode 2 is the Dusk/Dawn sensor
|
||||
device = ISYInsteonBinarySensorEntity(node, DEVICE_CLASS_LIGHT)
|
||||
|
@ -216,18 +215,10 @@ class ISYBinarySensorEntity(ISYNodeEntity, BinarySensorEntity):
|
|||
|
||||
@property
|
||||
def is_on(self) -> bool:
|
||||
"""Get whether the ISY994 binary sensor device is on.
|
||||
|
||||
Note: This method will return false if the current state is UNKNOWN
|
||||
"""
|
||||
return bool(self.value)
|
||||
|
||||
@property
|
||||
def state(self):
|
||||
"""Return the state of the binary sensor."""
|
||||
if self.value == ISY_VALUE_UNKNOWN:
|
||||
return STATE_UNKNOWN
|
||||
return STATE_ON if self.is_on else STATE_OFF
|
||||
"""Get whether the ISY994 binary sensor device is on."""
|
||||
if self._node.status == ISY_VALUE_UNKNOWN:
|
||||
return None
|
||||
return bool(self._node.status)
|
||||
|
||||
@property
|
||||
def device_class(self) -> str:
|
||||
|
@ -354,8 +345,8 @@ class ISYInsteonBinarySensorEntity(ISYBinarySensorEntity):
|
|||
self._heartbeat()
|
||||
|
||||
@property
|
||||
def value(self) -> object:
|
||||
"""Get the current value of the device.
|
||||
def is_on(self) -> bool:
|
||||
"""Get whether the ISY994 binary sensor device is on.
|
||||
|
||||
Insteon leak sensors set their primary node to On when the state is
|
||||
DRY, not WET, so we invert the binary state if the user indicates
|
||||
|
@ -370,13 +361,6 @@ class ISYInsteonBinarySensorEntity(ISYBinarySensorEntity):
|
|||
|
||||
return self._computed_state
|
||||
|
||||
@property
|
||||
def state(self):
|
||||
"""Return the state of the binary sensor."""
|
||||
if self._computed_state is None:
|
||||
return STATE_UNKNOWN
|
||||
return STATE_ON if self.is_on else STATE_OFF
|
||||
|
||||
|
||||
class ISYBinarySensorHeartbeat(ISYNodeEntity, BinarySensorEntity):
|
||||
"""Representation of the battery state of an ISY994 sensor."""
|
||||
|
@ -394,7 +378,7 @@ class ISYBinarySensorHeartbeat(ISYNodeEntity, BinarySensorEntity):
|
|||
self._parent_device = parent_device
|
||||
self._heartbeat_timer = None
|
||||
self._computed_state = None
|
||||
if self.state != STATE_UNKNOWN:
|
||||
if self.state is None:
|
||||
self._computed_state = False
|
||||
|
||||
async def async_added_to_hass(self) -> None:
|
||||
|
@ -459,25 +443,15 @@ class ISYBinarySensorHeartbeat(ISYNodeEntity, BinarySensorEntity):
|
|||
We listen directly to the Control events for this device.
|
||||
"""
|
||||
|
||||
@property
|
||||
def value(self) -> object:
|
||||
"""Get the current value of this sensor."""
|
||||
return self._computed_state
|
||||
|
||||
@property
|
||||
def is_on(self) -> bool:
|
||||
"""Get whether the ISY994 binary sensor device is on.
|
||||
|
||||
Note: This method will return false if the current state is UNKNOWN
|
||||
which occurs after a restart until the first heartbeat or control
|
||||
parent control event is received.
|
||||
"""
|
||||
return bool(self.value)
|
||||
|
||||
@property
|
||||
def state(self):
|
||||
"""Return the state of the binary sensor."""
|
||||
if self._computed_state is None:
|
||||
return None
|
||||
return STATE_ON if self.is_on else STATE_OFF
|
||||
return bool(self._computed_state)
|
||||
|
||||
@property
|
||||
def device_class(self) -> str:
|
||||
|
@ -502,4 +476,4 @@ class ISYBinarySensorProgramEntity(ISYProgramEntity, BinarySensorEntity):
|
|||
@property
|
||||
def is_on(self) -> bool:
|
||||
"""Get whether the ISY994 binary sensor device is on."""
|
||||
return bool(self.value)
|
||||
return bool(self._node.status)
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
"""Support for Insteon Thermostats via ISY994 Platform."""
|
||||
from typing import Callable, List, Optional, Union
|
||||
from typing import Callable, List, Optional
|
||||
|
||||
from pyisy.constants import (
|
||||
CMD_CLIMATE_FAN_SETTING,
|
||||
CMD_CLIMATE_MODE,
|
||||
ISY_VALUE_UNKNOWN,
|
||||
PROP_HEAT_COOL_STATE,
|
||||
PROP_HUMIDITY,
|
||||
PROP_SETPOINT_COOL,
|
||||
|
@ -42,19 +41,17 @@ from .const import (
|
|||
HA_HVAC_TO_ISY,
|
||||
ISY994_NODES,
|
||||
ISY_HVAC_MODES,
|
||||
UOM_DOUBLE_TEMP,
|
||||
UOM_FAN_MODES,
|
||||
UOM_HVAC_ACTIONS,
|
||||
UOM_HVAC_MODE_GENERIC,
|
||||
UOM_HVAC_MODE_INSTEON,
|
||||
UOM_ISY_CELSIUS,
|
||||
UOM_ISY_FAHRENHEIT,
|
||||
UOM_ISYV4_DEGREES,
|
||||
UOM_ISYV4_NONE,
|
||||
UOM_TO_STATES,
|
||||
)
|
||||
from .entity import ISYNodeEntity
|
||||
from .helpers import migrate_old_unique_ids
|
||||
from .helpers import convert_isy_value_to_hass, migrate_old_unique_ids
|
||||
from .services import async_setup_device_services
|
||||
|
||||
ISY_SUPPORTED_FEATURES = (
|
||||
|
@ -79,26 +76,6 @@ async def async_setup_entry(
|
|||
async_setup_device_services(hass)
|
||||
|
||||
|
||||
def convert_isy_temp_to_hass(
|
||||
temp: Union[int, float, None], uom: str, precision: str
|
||||
) -> float:
|
||||
"""Fix Insteon Thermostats' Reported Temperature.
|
||||
|
||||
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.
|
||||
|
||||
Z-Wave Thermostats report temps in tenths as an integer and precision.
|
||||
Correct by shifting the decimal place left by the value of precision.
|
||||
"""
|
||||
if temp is None or temp == ISY_VALUE_UNKNOWN:
|
||||
return None
|
||||
if uom in [UOM_DOUBLE_TEMP, UOM_ISYV4_DEGREES]:
|
||||
return round(float(temp) / 2.0, 1)
|
||||
if precision != "0":
|
||||
return round(float(temp) / 10 ** int(precision), int(precision))
|
||||
return round(float(temp), 1)
|
||||
|
||||
|
||||
class ISYThermostatEntity(ISYNodeEntity, ClimateEntity):
|
||||
"""Representation of an ISY994 thermostat entity."""
|
||||
|
||||
|
@ -180,7 +157,9 @@ class ISYThermostatEntity(ISYNodeEntity, ClimateEntity):
|
|||
@property
|
||||
def current_temperature(self) -> Optional[float]:
|
||||
"""Return the current temperature."""
|
||||
return convert_isy_temp_to_hass(self._node.status, self._uom, self._node.prec)
|
||||
return convert_isy_value_to_hass(
|
||||
self._node.status, self._uom, self._node.prec, 1
|
||||
)
|
||||
|
||||
@property
|
||||
def target_temperature_step(self) -> Optional[float]:
|
||||
|
@ -202,7 +181,7 @@ class ISYThermostatEntity(ISYNodeEntity, ClimateEntity):
|
|||
target = self._node.aux_properties.get(PROP_SETPOINT_COOL)
|
||||
if not target:
|
||||
return None
|
||||
return convert_isy_temp_to_hass(target.value, target.uom, target.prec)
|
||||
return convert_isy_value_to_hass(target.value, target.uom, target.prec, 1)
|
||||
|
||||
@property
|
||||
def target_temperature_low(self) -> Optional[float]:
|
||||
|
@ -210,7 +189,7 @@ class ISYThermostatEntity(ISYNodeEntity, ClimateEntity):
|
|||
target = self._node.aux_properties.get(PROP_SETPOINT_HEAT)
|
||||
if not target:
|
||||
return None
|
||||
return convert_isy_temp_to_hass(target.value, target.uom, target.prec)
|
||||
return convert_isy_value_to_hass(target.value, target.uom, target.prec, 1)
|
||||
|
||||
@property
|
||||
def fan_modes(self):
|
||||
|
|
|
@ -301,6 +301,8 @@ UOM_HVAC_ACTIONS = "66"
|
|||
UOM_HVAC_MODE_GENERIC = "67"
|
||||
UOM_HVAC_MODE_INSTEON = "98"
|
||||
UOM_FAN_MODES = "99"
|
||||
UOM_INDEX = "25"
|
||||
UOM_ON_OFF = "2"
|
||||
|
||||
UOM_FRIENDLY_NAME = {
|
||||
"1": "A",
|
||||
|
@ -324,7 +326,7 @@ UOM_FRIENDLY_NAME = {
|
|||
"22": "%RH",
|
||||
"23": PRESSURE_INHG,
|
||||
"24": f"{LENGTH_INCHES}/{TIME_HOURS}",
|
||||
"25": "index",
|
||||
UOM_INDEX: "index", # Index type. Use "node.formatted" for value
|
||||
"26": TEMP_KELVIN,
|
||||
"27": "keyword",
|
||||
"28": MASS_KILOGRAMS,
|
||||
|
@ -383,7 +385,7 @@ UOM_FRIENDLY_NAME = {
|
|||
"91": DEGREE,
|
||||
"92": f"{DEGREE} South",
|
||||
"100": "", # Range 0-255, no unit.
|
||||
"101": f"{DEGREE} (x2)",
|
||||
UOM_DOUBLE_TEMP: UOM_DOUBLE_TEMP,
|
||||
"102": "kWs",
|
||||
"103": "$",
|
||||
"104": "¢",
|
||||
|
@ -398,7 +400,7 @@ UOM_FRIENDLY_NAME = {
|
|||
"113": "", # raw 3-byte signed value
|
||||
"114": "", # raw 4-byte signed value
|
||||
"116": LENGTH_MILES,
|
||||
"117": "mb",
|
||||
"117": "mbar",
|
||||
"118": "hPa",
|
||||
"119": f"{POWER_WATT}{TIME_HOURS}",
|
||||
"120": f"{LENGTH_INCHES}/{TIME_DAYS}",
|
||||
|
|
|
@ -5,16 +5,9 @@ from pyisy.constants import ISY_VALUE_UNKNOWN
|
|||
|
||||
from homeassistant.components.cover import DOMAIN as COVER, CoverEntity
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import STATE_CLOSED, STATE_OPEN, STATE_UNKNOWN
|
||||
from homeassistant.helpers.typing import HomeAssistantType
|
||||
|
||||
from .const import (
|
||||
_LOGGER,
|
||||
DOMAIN as ISY994_DOMAIN,
|
||||
ISY994_NODES,
|
||||
ISY994_PROGRAMS,
|
||||
UOM_TO_STATES,
|
||||
)
|
||||
from .const import _LOGGER, DOMAIN as ISY994_DOMAIN, ISY994_NODES, ISY994_PROGRAMS
|
||||
from .entity import ISYNodeEntity, ISYProgramEntity
|
||||
from .helpers import migrate_old_unique_ids
|
||||
from .services import async_setup_device_services
|
||||
|
@ -45,21 +38,16 @@ class ISYCoverEntity(ISYNodeEntity, CoverEntity):
|
|||
@property
|
||||
def current_cover_position(self) -> int:
|
||||
"""Return the current cover position."""
|
||||
if self.value in [None, ISY_VALUE_UNKNOWN]:
|
||||
return STATE_UNKNOWN
|
||||
return sorted((0, self.value, 100))[1]
|
||||
if self._node.status == ISY_VALUE_UNKNOWN:
|
||||
return None
|
||||
return sorted((0, self._node.status, 100))[1]
|
||||
|
||||
@property
|
||||
def is_closed(self) -> bool:
|
||||
"""Get whether the ISY994 cover device is closed."""
|
||||
return self.state == STATE_CLOSED
|
||||
|
||||
@property
|
||||
def state(self) -> str:
|
||||
"""Get the state of the ISY994 cover device."""
|
||||
if self.value == ISY_VALUE_UNKNOWN:
|
||||
return STATE_UNKNOWN
|
||||
return UOM_TO_STATES["97"].get(self.value, STATE_OPEN)
|
||||
if self._node.status == ISY_VALUE_UNKNOWN:
|
||||
return None
|
||||
return self._node.status == 0
|
||||
|
||||
def open_cover(self, **kwargs) -> None:
|
||||
"""Send the open cover command to the ISY994 cover device."""
|
||||
|
@ -76,9 +64,9 @@ class ISYCoverProgramEntity(ISYProgramEntity, CoverEntity):
|
|||
"""Representation of an ISY994 cover program."""
|
||||
|
||||
@property
|
||||
def state(self) -> str:
|
||||
"""Get the state of the ISY994 cover program."""
|
||||
return STATE_CLOSED if bool(self.value) else STATE_OPEN
|
||||
def is_closed(self) -> bool:
|
||||
"""Get whether the ISY994 cover program is closed."""
|
||||
return bool(self._node.status)
|
||||
|
||||
def open_cover(self, **kwargs) -> None:
|
||||
"""Send the open cover command to the ISY994 cover program."""
|
||||
|
|
|
@ -4,13 +4,12 @@ from pyisy.constants import (
|
|||
COMMAND_FRIENDLY_NAME,
|
||||
EMPTY_TIME,
|
||||
EVENT_PROPS_IGNORED,
|
||||
ISY_VALUE_UNKNOWN,
|
||||
PROTO_GROUP,
|
||||
PROTO_ZWAVE,
|
||||
)
|
||||
from pyisy.helpers import NodeProperty
|
||||
|
||||
from homeassistant.const import STATE_OFF, STATE_ON, STATE_UNKNOWN
|
||||
from homeassistant.const import STATE_OFF, STATE_ON
|
||||
from homeassistant.helpers.entity import Entity
|
||||
from homeassistant.helpers.typing import Dict
|
||||
|
||||
|
@ -51,7 +50,7 @@ class ISYEntity(Entity):
|
|||
"precision": event.prec,
|
||||
}
|
||||
|
||||
if event.value is None or event.control not in EVENT_PROPS_IGNORED:
|
||||
if event.control not in EVENT_PROPS_IGNORED:
|
||||
# New state attributes may be available, update the state.
|
||||
self.schedule_update_ha_state()
|
||||
|
||||
|
@ -128,18 +127,6 @@ class ISYEntity(Entity):
|
|||
"""No polling required since we're using the subscription."""
|
||||
return False
|
||||
|
||||
@property
|
||||
def value(self) -> int:
|
||||
"""Get the current value of the device."""
|
||||
return self._node.status
|
||||
|
||||
@property
|
||||
def state(self):
|
||||
"""Return the state of the ISY device."""
|
||||
if self.value == ISY_VALUE_UNKNOWN:
|
||||
return STATE_UNKNOWN
|
||||
return super().state
|
||||
|
||||
|
||||
class ISYNodeEntity(ISYEntity):
|
||||
"""Representation of a ISY Nodebase (Node/Group) entity."""
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
"""Support for ISY994 fans."""
|
||||
from typing import Callable
|
||||
|
||||
from pyisy.constants import ISY_VALUE_UNKNOWN
|
||||
|
||||
from homeassistant.components.fan import (
|
||||
DOMAIN as FAN,
|
||||
SPEED_HIGH,
|
||||
|
@ -58,12 +60,14 @@ class ISYFanEntity(ISYNodeEntity, FanEntity):
|
|||
@property
|
||||
def speed(self) -> str:
|
||||
"""Return the current speed."""
|
||||
return VALUE_TO_STATE.get(self.value)
|
||||
return VALUE_TO_STATE.get(self._node.status)
|
||||
|
||||
@property
|
||||
def is_on(self) -> bool:
|
||||
"""Get if the fan is on."""
|
||||
return self.value != 0
|
||||
if self._node.status == ISY_VALUE_UNKNOWN:
|
||||
return None
|
||||
return self._node.status != 0
|
||||
|
||||
def set_speed(self, speed: str) -> None:
|
||||
"""Send the set speed command to the ISY994 fan device."""
|
||||
|
@ -94,12 +98,12 @@ class ISYFanProgramEntity(ISYProgramEntity, FanEntity):
|
|||
@property
|
||||
def speed(self) -> str:
|
||||
"""Return the current speed."""
|
||||
return VALUE_TO_STATE.get(self.value)
|
||||
return VALUE_TO_STATE.get(self._node.status)
|
||||
|
||||
@property
|
||||
def is_on(self) -> bool:
|
||||
"""Get if the fan is on."""
|
||||
return self.value != 0
|
||||
return self._node.status != 0
|
||||
|
||||
def turn_off(self, **kwargs) -> None:
|
||||
"""Send the turn on command to ISY994 fan program."""
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
from typing import Any, List, Optional, Union
|
||||
|
||||
from pyisy.constants import (
|
||||
ISY_VALUE_UNKNOWN,
|
||||
PROTO_GROUP,
|
||||
PROTO_INSTEON,
|
||||
PROTO_PROGRAM,
|
||||
|
@ -46,6 +47,8 @@ from .const import (
|
|||
SUPPORTED_PROGRAM_PLATFORMS,
|
||||
TYPE_CATEGORY_SENSOR_ACTUATORS,
|
||||
TYPE_EZIO2X4,
|
||||
UOM_DOUBLE_TEMP,
|
||||
UOM_ISYV4_DEGREES,
|
||||
)
|
||||
|
||||
BINARY_SENSOR_UOMS = ["2", "78"]
|
||||
|
@ -394,3 +397,29 @@ async def migrate_old_unique_ids(
|
|||
registry.async_update_entity(
|
||||
old_entity_id_2, new_unique_id=device.unique_id
|
||||
)
|
||||
|
||||
|
||||
def convert_isy_value_to_hass(
|
||||
value: Union[int, float, None],
|
||||
uom: str,
|
||||
precision: str,
|
||||
fallback_precision: Optional[int] = None,
|
||||
) -> Union[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, prec="2" == 23.45)
|
||||
|
||||
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.
|
||||
"""
|
||||
if value is None or value == ISY_VALUE_UNKNOWN:
|
||||
return None
|
||||
if uom in [UOM_DOUBLE_TEMP, UOM_ISYV4_DEGREES]:
|
||||
return round(float(value) / 2.0, 1)
|
||||
if precision != "0":
|
||||
return round(float(value) / 10 ** int(precision), int(precision))
|
||||
if fallback_precision:
|
||||
return round(float(value), fallback_precision)
|
||||
return value
|
||||
|
|
|
@ -9,7 +9,6 @@ from homeassistant.components.light import (
|
|||
LightEntity,
|
||||
)
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import STATE_UNKNOWN
|
||||
from homeassistant.helpers.restore_state import RestoreEntity
|
||||
from homeassistant.helpers.typing import HomeAssistantType
|
||||
|
||||
|
@ -58,14 +57,16 @@ class ISYLightEntity(ISYNodeEntity, LightEntity, RestoreEntity):
|
|||
@property
|
||||
def is_on(self) -> bool:
|
||||
"""Get whether the ISY994 light is on."""
|
||||
if self.value == ISY_VALUE_UNKNOWN:
|
||||
if self._node.status == ISY_VALUE_UNKNOWN:
|
||||
return False
|
||||
return int(self.value) != 0
|
||||
return int(self._node.status) != 0
|
||||
|
||||
@property
|
||||
def brightness(self) -> float:
|
||||
"""Get the brightness of the ISY994 light."""
|
||||
return STATE_UNKNOWN if self.value == ISY_VALUE_UNKNOWN else int(self.value)
|
||||
if self._node.status == ISY_VALUE_UNKNOWN:
|
||||
return None
|
||||
return int(self._node.status)
|
||||
|
||||
def turn_off(self, **kwargs) -> None:
|
||||
"""Send the turn off command to the ISY994 light device."""
|
||||
|
@ -75,8 +76,8 @@ class ISYLightEntity(ISYNodeEntity, LightEntity, RestoreEntity):
|
|||
|
||||
def on_update(self, event: object) -> None:
|
||||
"""Save brightness in the update event from the ISY994 Node."""
|
||||
if self.value not in (0, ISY_VALUE_UNKNOWN):
|
||||
self._last_brightness = self.value
|
||||
if self._node.status not in (0, ISY_VALUE_UNKNOWN):
|
||||
self._last_brightness = self._node.status
|
||||
super().on_update(event)
|
||||
|
||||
# pylint: disable=arguments-differ
|
||||
|
|
|
@ -5,7 +5,6 @@ from pyisy.constants import ISY_VALUE_UNKNOWN
|
|||
|
||||
from homeassistant.components.lock import DOMAIN as LOCK, LockEntity
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import STATE_LOCKED, STATE_UNKNOWN, STATE_UNLOCKED
|
||||
from homeassistant.helpers.typing import HomeAssistantType
|
||||
|
||||
from .const import _LOGGER, DOMAIN as ISY994_DOMAIN, ISY994_NODES, ISY994_PROGRAMS
|
||||
|
@ -13,7 +12,7 @@ from .entity import ISYNodeEntity, ISYProgramEntity
|
|||
from .helpers import migrate_old_unique_ids
|
||||
from .services import async_setup_device_services
|
||||
|
||||
VALUE_TO_STATE = {0: STATE_UNLOCKED, 100: STATE_LOCKED}
|
||||
VALUE_TO_STATE = {0: False, 100: True}
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
|
@ -41,29 +40,20 @@ class ISYLockEntity(ISYNodeEntity, LockEntity):
|
|||
@property
|
||||
def is_locked(self) -> bool:
|
||||
"""Get whether the lock is in locked state."""
|
||||
return self.state == STATE_LOCKED
|
||||
|
||||
@property
|
||||
def state(self) -> str:
|
||||
"""Get the state of the lock."""
|
||||
if self.value == ISY_VALUE_UNKNOWN:
|
||||
return STATE_UNKNOWN
|
||||
return VALUE_TO_STATE.get(self.value, STATE_UNKNOWN)
|
||||
if self._node.status == ISY_VALUE_UNKNOWN:
|
||||
return None
|
||||
return VALUE_TO_STATE.get(self._node.status)
|
||||
|
||||
def lock(self, **kwargs) -> None:
|
||||
"""Send the lock command to the ISY994 device."""
|
||||
if not self._node.secure_lock():
|
||||
_LOGGER.error("Unable to lock device")
|
||||
|
||||
self._node.update(0.5)
|
||||
|
||||
def unlock(self, **kwargs) -> None:
|
||||
"""Send the unlock command to the ISY994 device."""
|
||||
if not self._node.secure_unlock():
|
||||
_LOGGER.error("Unable to lock device")
|
||||
|
||||
self._node.update(0.5)
|
||||
|
||||
|
||||
class ISYLockProgramEntity(ISYProgramEntity, LockEntity):
|
||||
"""Representation of a ISY lock program."""
|
||||
|
@ -71,12 +61,7 @@ class ISYLockProgramEntity(ISYProgramEntity, LockEntity):
|
|||
@property
|
||||
def is_locked(self) -> bool:
|
||||
"""Return true if the device is locked."""
|
||||
return bool(self.value)
|
||||
|
||||
@property
|
||||
def state(self) -> str:
|
||||
"""Return the state of the lock."""
|
||||
return STATE_LOCKED if self.is_locked else STATE_UNLOCKED
|
||||
return bool(self._node.status)
|
||||
|
||||
def lock(self, **kwargs) -> None:
|
||||
"""Lock the device."""
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
"""Support for ISY994 sensors."""
|
||||
from typing import Callable, Dict
|
||||
from typing import Callable, Dict, Union
|
||||
|
||||
from pyisy.constants import ISY_VALUE_UNKNOWN
|
||||
|
||||
from homeassistant.components.sensor import DOMAIN as SENSOR
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import STATE_UNKNOWN, TEMP_CELSIUS, TEMP_FAHRENHEIT
|
||||
from homeassistant.const import TEMP_CELSIUS, TEMP_FAHRENHEIT
|
||||
from homeassistant.helpers.typing import HomeAssistantType
|
||||
|
||||
from .const import (
|
||||
|
@ -13,11 +13,12 @@ from .const import (
|
|||
DOMAIN as ISY994_DOMAIN,
|
||||
ISY994_NODES,
|
||||
ISY994_VARIABLES,
|
||||
UOM_DOUBLE_TEMP,
|
||||
UOM_FRIENDLY_NAME,
|
||||
UOM_TO_STATES,
|
||||
)
|
||||
from .entity import ISYEntity, ISYNodeEntity
|
||||
from .helpers import migrate_old_unique_ids
|
||||
from .helpers import convert_isy_value_to_hass, migrate_old_unique_ids
|
||||
from .services import async_setup_device_services
|
||||
|
||||
|
||||
|
@ -46,48 +47,52 @@ class ISYSensorEntity(ISYNodeEntity):
|
|||
"""Representation of an ISY994 sensor device."""
|
||||
|
||||
@property
|
||||
def raw_unit_of_measurement(self) -> str:
|
||||
def raw_unit_of_measurement(self) -> Union[dict, str]:
|
||||
"""Get the raw unit of measurement for the ISY994 sensor device."""
|
||||
uom = self._node.uom
|
||||
|
||||
# Backwards compatibility for ISYv4 Firmware:
|
||||
if isinstance(uom, list):
|
||||
return UOM_FRIENDLY_NAME.get(uom[0], uom[0])
|
||||
|
||||
# Special cases for ISY UOM index units:
|
||||
isy_states = UOM_TO_STATES.get(uom)
|
||||
if isy_states:
|
||||
return isy_states
|
||||
|
||||
return UOM_FRIENDLY_NAME.get(uom)
|
||||
|
||||
@property
|
||||
def state(self) -> str:
|
||||
"""Get the state of the ISY994 sensor device."""
|
||||
if self.value == ISY_VALUE_UNKNOWN:
|
||||
return STATE_UNKNOWN
|
||||
value = self._node.status
|
||||
if value == ISY_VALUE_UNKNOWN:
|
||||
return None
|
||||
|
||||
uom = self._node.uom
|
||||
# Backwards compatibility for ISYv4 Firmware:
|
||||
if isinstance(uom, list):
|
||||
uom = uom[0]
|
||||
if not uom:
|
||||
return STATE_UNKNOWN
|
||||
# Get the translated ISY Unit of Measurement
|
||||
uom = self.raw_unit_of_measurement
|
||||
|
||||
states = UOM_TO_STATES.get(uom)
|
||||
if states and states.get(self.value):
|
||||
return states.get(self.value)
|
||||
if self._node.prec and int(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 val
|
||||
return self.value
|
||||
# Check if this is a known index pair UOM
|
||||
if isinstance(uom, dict):
|
||||
return uom.get(value, value)
|
||||
|
||||
# Handle ISY precision and rounding
|
||||
value = convert_isy_value_to_hass(value, uom, self._node.prec)
|
||||
|
||||
# Convert temperatures to Home Assistant's unit
|
||||
if uom in (TEMP_CELSIUS, TEMP_FAHRENHEIT):
|
||||
value = self.hass.config.units.temperature(value, uom)
|
||||
|
||||
return value
|
||||
|
||||
@property
|
||||
def unit_of_measurement(self) -> str:
|
||||
"""Get the unit of measurement for the ISY994 sensor device."""
|
||||
"""Get the Home Assistant unit of measurement for the device."""
|
||||
raw_units = self.raw_unit_of_measurement
|
||||
if raw_units in (TEMP_FAHRENHEIT, TEMP_CELSIUS):
|
||||
# Check if this is a known index pair UOM
|
||||
if isinstance(raw_units, dict):
|
||||
return None
|
||||
if raw_units in (TEMP_FAHRENHEIT, TEMP_CELSIUS, UOM_DOUBLE_TEMP):
|
||||
return self.hass.config.units.temperature_unit
|
||||
return raw_units
|
||||
|
||||
|
@ -103,7 +108,7 @@ class ISYSensorVariableEntity(ISYEntity):
|
|||
@property
|
||||
def state(self):
|
||||
"""Return the state of the variable."""
|
||||
return self.value
|
||||
return self._node.status
|
||||
|
||||
@property
|
||||
def device_state_attributes(self) -> Dict:
|
||||
|
|
|
@ -5,7 +5,6 @@ from pyisy.constants import ISY_VALUE_UNKNOWN, PROTO_GROUP
|
|||
|
||||
from homeassistant.components.switch import DOMAIN as SWITCH, SwitchEntity
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import STATE_UNKNOWN
|
||||
from homeassistant.helpers.typing import HomeAssistantType
|
||||
|
||||
from .const import _LOGGER, DOMAIN as ISY994_DOMAIN, ISY994_NODES, ISY994_PROGRAMS
|
||||
|
@ -39,9 +38,9 @@ class ISYSwitchEntity(ISYNodeEntity, SwitchEntity):
|
|||
@property
|
||||
def is_on(self) -> bool:
|
||||
"""Get whether the ISY994 device is in the on state."""
|
||||
if self.value == ISY_VALUE_UNKNOWN:
|
||||
return STATE_UNKNOWN
|
||||
return bool(self.value)
|
||||
if self._node.status == ISY_VALUE_UNKNOWN:
|
||||
return None
|
||||
return bool(self._node.status)
|
||||
|
||||
def turn_off(self, **kwargs) -> None:
|
||||
"""Send the turn off command to the ISY994 switch."""
|
||||
|
@ -67,7 +66,7 @@ class ISYSwitchProgramEntity(ISYProgramEntity, SwitchEntity):
|
|||
@property
|
||||
def is_on(self) -> bool:
|
||||
"""Get whether the ISY994 switch program is on."""
|
||||
return bool(self.value)
|
||||
return bool(self._node.status)
|
||||
|
||||
def turn_on(self, **kwargs) -> None:
|
||||
"""Send the turn on command to the ISY994 switch program."""
|
||||
|
|
Loading…
Add table
Reference in a new issue