Add enable/disable config switch for ISY994 devices (#85975)

Co-authored-by: J. Nick Koston <nick@koston.org>
pull/86013/head^2
shbatm 2023-01-16 13:33:55 -06:00 committed by GitHub
parent b087c1e734
commit 3aad153913
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 116 additions and 11 deletions

View File

@ -87,7 +87,12 @@ NODE_PLATFORMS = [
Platform.SENSOR,
Platform.SWITCH,
]
NODE_AUX_PROP_PLATFORMS = [Platform.SELECT, Platform.SENSOR, Platform.NUMBER]
NODE_AUX_PROP_PLATFORMS = [
Platform.NUMBER,
Platform.SELECT,
Platform.SENSOR,
Platform.SWITCH,
]
PROGRAM_PLATFORMS = [
Platform.BINARY_SENSOR,
Platform.COVER,

View File

@ -16,6 +16,7 @@ from pyisy.constants import (
PROTO_INSTEON,
PROTO_PROGRAM,
PROTO_ZWAVE,
TAG_ENABLED,
TAG_FOLDER,
UOM_INDEX,
)
@ -349,6 +350,8 @@ def _categorize_nodes(
isy_data.aux_properties[Platform.SENSOR].append((node, control))
platform = NODE_AUX_FILTERS[control]
isy_data.aux_properties[platform].append((node, control))
if hasattr(node, TAG_ENABLED):
isy_data.aux_properties[Platform.SWITCH].append((node, TAG_ENABLED))
_add_backlight_if_supported(isy_data, node)
if node.protocol == PROTO_GROUP:

View File

@ -3,16 +3,30 @@ from __future__ import annotations
from typing import Any
from pyisy.constants import ISY_VALUE_UNKNOWN, PROTO_GROUP
from pyisy.constants import (
ATTR_ACTION,
ISY_VALUE_UNKNOWN,
NC_NODE_ENABLED,
PROTO_GROUP,
TAG_ADDRESS,
)
from pyisy.helpers import EventListener
from pyisy.nodes import Node, NodeChangedEvent
from homeassistant.components.switch import SwitchEntity
from homeassistant.components.switch import (
SwitchDeviceClass,
SwitchEntity,
SwitchEntityDescription,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import Platform
from homeassistant.core import HomeAssistant
from homeassistant.core import HomeAssistant, callback
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers.entity import DeviceInfo, EntityCategory, EntityDescription
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from .const import _LOGGER, DOMAIN
from .entity import ISYNodeEntity, ISYProgramEntity
from .const import DOMAIN
from .entity import ISYAuxControlEntity, ISYNodeEntity, ISYProgramEntity
from .models import IsyData
@ -21,7 +35,9 @@ async def async_setup_entry(
) -> None:
"""Set up the ISY switch platform."""
isy_data: IsyData = hass.data[DOMAIN][entry.entry_id]
entities: list[ISYSwitchProgramEntity | ISYSwitchEntity] = []
entities: list[
ISYSwitchProgramEntity | ISYSwitchEntity | ISYEnableSwitchEntity
] = []
device_info = isy_data.devices
for node in isy_data.nodes[Platform.SWITCH]:
primary = node.primary_node
@ -34,6 +50,24 @@ async def async_setup_entry(
for name, status, actions in isy_data.programs[Platform.SWITCH]:
entities.append(ISYSwitchProgramEntity(name, status, actions))
for node, control in isy_data.aux_properties[Platform.SWITCH]:
# Currently only used for enable switches, will need to be updated for NS support
# by making sure control == TAG_ENABLED
description = SwitchEntityDescription(
key=control,
device_class=SwitchDeviceClass.SWITCH,
name=control.title(),
entity_category=EntityCategory.CONFIG,
)
entities.append(
ISYEnableSwitchEntity(
node=node,
control=control,
unique_id=f"{isy_data.uid_base(node)}_{control}",
description=description,
device_info=device_info.get(node.primary_node),
)
)
async_add_entities(entities)
@ -50,12 +84,12 @@ class ISYSwitchEntity(ISYNodeEntity, SwitchEntity):
async def async_turn_off(self, **kwargs: Any) -> None:
"""Send the turn off command to the ISY switch."""
if not await self._node.turn_off():
_LOGGER.debug("Unable to turn off switch")
HomeAssistantError(f"Unable to turn off switch {self._node.address}")
async def async_turn_on(self, **kwargs: Any) -> None:
"""Send the turn on command to the ISY switch."""
if not await self._node.turn_on():
_LOGGER.debug("Unable to turn on switch")
HomeAssistantError(f"Unable to turn on switch {self._node.address}")
@property
def icon(self) -> str | None:
@ -76,14 +110,77 @@ class ISYSwitchProgramEntity(ISYProgramEntity, SwitchEntity):
async def async_turn_on(self, **kwargs: Any) -> None:
"""Send the turn on command to the ISY switch program."""
if not await self._actions.run_then():
_LOGGER.error("Unable to turn on switch")
HomeAssistantError(
f"Unable to run 'then' clause on program switch {self._actions.address}"
)
async def async_turn_off(self, **kwargs: Any) -> None:
"""Send the turn off command to the ISY switch program."""
if not await self._actions.run_else():
_LOGGER.error("Unable to turn off switch")
HomeAssistantError(
f"Unable to run 'else' clause on program switch {self._actions.address}"
)
@property
def icon(self) -> str:
"""Get the icon for programs."""
return "mdi:script-text-outline" # Matches isy program icon
class ISYEnableSwitchEntity(ISYAuxControlEntity, SwitchEntity):
"""A representation of an ISY enable/disable switch."""
def __init__(
self,
node: Node,
control: str,
unique_id: str,
description: EntityDescription,
device_info: DeviceInfo | None,
) -> None:
"""Initialize the ISY Aux Control Number entity."""
super().__init__(
node=node,
control=control,
unique_id=unique_id,
description=description,
device_info=device_info,
)
self._attr_name = description.name # Override super
self._change_handler: EventListener = None
async def async_added_to_hass(self) -> None:
"""Subscribe to the node control change events."""
self._change_handler = self._node.isy.nodes.status_events.subscribe(
self.async_on_update,
event_filter={
TAG_ADDRESS: self._node.address,
ATTR_ACTION: NC_NODE_ENABLED,
},
key=self.unique_id,
)
@callback
def async_on_update(self, event: NodeChangedEvent, key: str) -> None:
"""Handle a control event from the ISY Node."""
self.async_write_ha_state()
@property
def available(self) -> bool:
"""Return entity availability."""
return True # Enable switch is always available
@property
def is_on(self) -> bool | None:
"""Get whether the ISY device is in the on state."""
return bool(self._node.enabled)
async def async_turn_off(self, **kwargs: Any) -> None:
"""Send the turn off command to the ISY switch."""
if not await self._node.disable():
raise HomeAssistantError(f"Unable to disable device {self._node.address}")
async def async_turn_on(self, **kwargs: Any) -> None:
"""Send the turn on command to the ISY switch."""
if not await self._node.enable():
raise HomeAssistantError(f"Unable to enable device {self._node.address}")