mirror of
https://github.com/home-assistant/core.git
synced 2025-07-25 06:07:17 +00:00
Add device to Lutron (#107467)
* Add typing to Lutron platforms * Add devices to Lutron * Add devices to Lutron * Fix typing * Fix * Add name * Fix lights * Comment out ESA * Fix domain * Fix domain * Fix * Make generic keypad base class
This commit is contained in:
parent
43daf20be3
commit
d0da457a04
@ -17,6 +17,7 @@ from homeassistant.const import (
|
|||||||
from homeassistant.core import DOMAIN as HOMEASSISTANT_DOMAIN, HomeAssistant
|
from homeassistant.core import DOMAIN as HOMEASSISTANT_DOMAIN, HomeAssistant
|
||||||
from homeassistant.data_entry_flow import FlowResultType
|
from homeassistant.data_entry_flow import FlowResultType
|
||||||
import homeassistant.helpers.config_validation as cv
|
import homeassistant.helpers.config_validation as cv
|
||||||
|
import homeassistant.helpers.device_registry as dr
|
||||||
from homeassistant.helpers.issue_registry import IssueSeverity, async_create_issue
|
from homeassistant.helpers.issue_registry import IssueSeverity, async_create_issue
|
||||||
from homeassistant.helpers.typing import ConfigType
|
from homeassistant.helpers.typing import ConfigType
|
||||||
from homeassistant.util import slugify
|
from homeassistant.util import slugify
|
||||||
@ -167,7 +168,7 @@ class LutronData:
|
|||||||
buttons: list[LutronButton]
|
buttons: list[LutronButton]
|
||||||
covers: list[tuple[str, Output]]
|
covers: list[tuple[str, Output]]
|
||||||
lights: list[tuple[str, Output]]
|
lights: list[tuple[str, Output]]
|
||||||
scenes: list[tuple[str, str, Button, Led]]
|
scenes: list[tuple[str, Keypad, Button, Led]]
|
||||||
switches: list[tuple[str, Output]]
|
switches: list[tuple[str, Output]]
|
||||||
|
|
||||||
|
|
||||||
@ -218,11 +219,20 @@ async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> b
|
|||||||
(led for led in keypad.leds if led.number == button.number),
|
(led for led in keypad.leds if led.number == button.number),
|
||||||
None,
|
None,
|
||||||
)
|
)
|
||||||
entry_data.scenes.append((area.name, keypad.name, button, led))
|
entry_data.scenes.append((area.name, keypad, button, led))
|
||||||
|
|
||||||
entry_data.buttons.append(LutronButton(hass, area.name, keypad, button))
|
entry_data.buttons.append(LutronButton(hass, area.name, keypad, button))
|
||||||
if area.occupancy_group is not None:
|
if area.occupancy_group is not None:
|
||||||
entry_data.binary_sensors.append((area.name, area.occupancy_group))
|
entry_data.binary_sensors.append((area.name, area.occupancy_group))
|
||||||
|
|
||||||
|
device_registry = dr.async_get(hass)
|
||||||
|
device_registry.async_get_or_create(
|
||||||
|
config_entry_id=config_entry.entry_id,
|
||||||
|
identifiers={(DOMAIN, lutron_client.guid)},
|
||||||
|
manufacturer="Lutron",
|
||||||
|
name="Main repeater",
|
||||||
|
)
|
||||||
|
|
||||||
hass.data.setdefault(DOMAIN, {})[config_entry.entry_id] = entry_data
|
hass.data.setdefault(DOMAIN, {})[config_entry.entry_id] = entry_data
|
||||||
|
|
||||||
await hass.config_entries.async_forward_entry_setups(config_entry, PLATFORMS)
|
await hass.config_entries.async_forward_entry_setups(config_entry, PLATFORMS)
|
||||||
|
@ -58,14 +58,6 @@ class LutronOccupancySensor(LutronDevice, BinarySensorEntity):
|
|||||||
# Error cases will end up treated as unoccupied.
|
# Error cases will end up treated as unoccupied.
|
||||||
return self._lutron_device.state == OccupancyGroup.State.OCCUPIED
|
return self._lutron_device.state == OccupancyGroup.State.OCCUPIED
|
||||||
|
|
||||||
@property
|
|
||||||
def name(self) -> str:
|
|
||||||
"""Return the name of the device."""
|
|
||||||
# The default LutronDevice naming would create 'Kitchen Occ Kitchen',
|
|
||||||
# but since there can only be one OccupancyGroup per area we go
|
|
||||||
# with something shorter.
|
|
||||||
return f"{self._area_name} Occupancy"
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def extra_state_attributes(self) -> Mapping[str, Any] | None:
|
def extra_state_attributes(self) -> Mapping[str, Any] | None:
|
||||||
"""Return the state attributes."""
|
"""Return the state attributes."""
|
||||||
|
@ -51,6 +51,7 @@ class LutronCover(LutronDevice, CoverEntity):
|
|||||||
| CoverEntityFeature.SET_POSITION
|
| CoverEntityFeature.SET_POSITION
|
||||||
)
|
)
|
||||||
_lutron_device: Output
|
_lutron_device: Output
|
||||||
|
_attr_name = None
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_closed(self) -> bool:
|
def is_closed(self) -> bool:
|
||||||
|
@ -1,14 +1,19 @@
|
|||||||
"""Base class for Lutron devices."""
|
"""Base class for Lutron devices."""
|
||||||
|
|
||||||
from pylutron import Lutron, LutronEntity, LutronEvent
|
from pylutron import Keypad, Lutron, LutronEntity, LutronEvent
|
||||||
|
|
||||||
|
from homeassistant.const import ATTR_IDENTIFIERS, ATTR_VIA_DEVICE
|
||||||
|
from homeassistant.helpers.device_registry import DeviceInfo
|
||||||
from homeassistant.helpers.entity import Entity
|
from homeassistant.helpers.entity import Entity
|
||||||
|
|
||||||
|
from .const import DOMAIN
|
||||||
|
|
||||||
class LutronDevice(Entity):
|
|
||||||
"""Representation of a Lutron device entity."""
|
class LutronBaseEntity(Entity):
|
||||||
|
"""Base class for Lutron entities."""
|
||||||
|
|
||||||
_attr_should_poll = False
|
_attr_should_poll = False
|
||||||
|
_attr_has_entity_name = True
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self, area_name: str, lutron_device: LutronEntity, controller: Lutron
|
self, area_name: str, lutron_device: LutronEntity, controller: Lutron
|
||||||
@ -28,11 +33,6 @@ class LutronDevice(Entity):
|
|||||||
"""Run when invoked by pylutron when the device state changes."""
|
"""Run when invoked by pylutron when the device state changes."""
|
||||||
self.schedule_update_ha_state()
|
self.schedule_update_ha_state()
|
||||||
|
|
||||||
@property
|
|
||||||
def name(self) -> str:
|
|
||||||
"""Return the name of the device."""
|
|
||||||
return f"{self._area_name} {self._lutron_device.name}"
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def unique_id(self) -> str | None:
|
def unique_id(self) -> str | None:
|
||||||
"""Return a unique ID."""
|
"""Return a unique ID."""
|
||||||
@ -40,3 +40,43 @@ class LutronDevice(Entity):
|
|||||||
if self._lutron_device.uuid is None:
|
if self._lutron_device.uuid is None:
|
||||||
return None
|
return None
|
||||||
return f"{self._controller.guid}_{self._lutron_device.uuid}"
|
return f"{self._controller.guid}_{self._lutron_device.uuid}"
|
||||||
|
|
||||||
|
|
||||||
|
class LutronDevice(LutronBaseEntity):
|
||||||
|
"""Representation of a Lutron device entity."""
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self, area_name: str, lutron_device: LutronEntity, controller: Lutron
|
||||||
|
) -> None:
|
||||||
|
"""Initialize the device."""
|
||||||
|
super().__init__(area_name, lutron_device, controller)
|
||||||
|
self._attr_device_info = DeviceInfo(
|
||||||
|
identifiers={(DOMAIN, lutron_device.uuid)},
|
||||||
|
manufacturer="Lutron",
|
||||||
|
name=lutron_device.name,
|
||||||
|
suggested_area=area_name,
|
||||||
|
via_device=(DOMAIN, controller.guid),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class LutronKeypad(LutronBaseEntity):
|
||||||
|
"""Representation of a Lutron Keypad."""
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
area_name: str,
|
||||||
|
lutron_device: LutronEntity,
|
||||||
|
controller: Lutron,
|
||||||
|
keypad: Keypad,
|
||||||
|
) -> None:
|
||||||
|
"""Initialize the device."""
|
||||||
|
super().__init__(area_name, lutron_device, controller)
|
||||||
|
self._attr_device_info = DeviceInfo(
|
||||||
|
identifiers={(DOMAIN, keypad.id)},
|
||||||
|
manufacturer="Lutron",
|
||||||
|
name=keypad.name,
|
||||||
|
)
|
||||||
|
if keypad.type == "MAIN_REPEATER":
|
||||||
|
self._attr_device_info[ATTR_IDENTIFIERS].add((DOMAIN, controller.guid))
|
||||||
|
else:
|
||||||
|
self._attr_device_info[ATTR_VIA_DEVICE] = (DOMAIN, controller.guid)
|
||||||
|
@ -52,6 +52,7 @@ class LutronLight(LutronDevice, LightEntity):
|
|||||||
_attr_supported_color_modes = {ColorMode.BRIGHTNESS}
|
_attr_supported_color_modes = {ColorMode.BRIGHTNESS}
|
||||||
_lutron_device: Output
|
_lutron_device: Output
|
||||||
_prev_brightness: int | None = None
|
_prev_brightness: int | None = None
|
||||||
|
_attr_name = None
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def brightness(self) -> int:
|
def brightness(self) -> int:
|
||||||
|
@ -3,7 +3,7 @@ from __future__ import annotations
|
|||||||
|
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
from pylutron import Button, Led, Lutron
|
from pylutron import Button, Keypad, Lutron
|
||||||
|
|
||||||
from homeassistant.components.scene import Scene
|
from homeassistant.components.scene import Scene
|
||||||
from homeassistant.config_entries import ConfigEntry
|
from homeassistant.config_entries import ConfigEntry
|
||||||
@ -11,7 +11,7 @@ from homeassistant.core import HomeAssistant
|
|||||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
|
|
||||||
from . import DOMAIN, LutronData
|
from . import DOMAIN, LutronData
|
||||||
from .entity import LutronDevice
|
from .entity import LutronKeypad
|
||||||
|
|
||||||
|
|
||||||
async def async_setup_entry(
|
async def async_setup_entry(
|
||||||
@ -28,14 +28,14 @@ async def async_setup_entry(
|
|||||||
|
|
||||||
async_add_entities(
|
async_add_entities(
|
||||||
[
|
[
|
||||||
LutronScene(area_name, keypad_name, device, led, entry_data.client)
|
LutronScene(area_name, keypad, device, entry_data.client)
|
||||||
for area_name, keypad_name, device, led in entry_data.scenes
|
for area_name, keypad, device, led in entry_data.scenes
|
||||||
],
|
],
|
||||||
True,
|
True,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class LutronScene(LutronDevice, Scene):
|
class LutronScene(LutronKeypad, Scene):
|
||||||
"""Representation of a Lutron Scene."""
|
"""Representation of a Lutron Scene."""
|
||||||
|
|
||||||
_lutron_device: Button
|
_lutron_device: Button
|
||||||
@ -43,21 +43,14 @@ class LutronScene(LutronDevice, Scene):
|
|||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
area_name: str,
|
area_name: str,
|
||||||
keypad_name: str,
|
keypad: Keypad,
|
||||||
lutron_device: Button,
|
lutron_device: Button,
|
||||||
lutron_led: Led,
|
|
||||||
controller: Lutron,
|
controller: Lutron,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Initialize the scene/button."""
|
"""Initialize the scene/button."""
|
||||||
super().__init__(area_name, lutron_device, controller)
|
super().__init__(area_name, lutron_device, controller, keypad)
|
||||||
self._keypad_name = keypad_name
|
self._attr_name = lutron_device.name
|
||||||
self._led = lutron_led
|
|
||||||
|
|
||||||
def activate(self, **kwargs: Any) -> None:
|
def activate(self, **kwargs: Any) -> None:
|
||||||
"""Activate the scene."""
|
"""Activate the scene."""
|
||||||
self._lutron_device.press()
|
self._lutron_device.press()
|
||||||
|
|
||||||
@property
|
|
||||||
def name(self) -> str:
|
|
||||||
"""Return the name of the device."""
|
|
||||||
return f"{self._area_name} {self._keypad_name}: {self._lutron_device.name}"
|
|
||||||
|
@ -4,7 +4,7 @@ from __future__ import annotations
|
|||||||
from collections.abc import Mapping
|
from collections.abc import Mapping
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
from pylutron import Button, Led, Lutron, Output
|
from pylutron import Button, Keypad, Led, Lutron, Output
|
||||||
|
|
||||||
from homeassistant.components.switch import SwitchEntity
|
from homeassistant.components.switch import SwitchEntity
|
||||||
from homeassistant.config_entries import ConfigEntry
|
from homeassistant.config_entries import ConfigEntry
|
||||||
@ -12,7 +12,7 @@ from homeassistant.core import HomeAssistant
|
|||||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
|
|
||||||
from . import DOMAIN, LutronData
|
from . import DOMAIN, LutronData
|
||||||
from .entity import LutronDevice
|
from .entity import LutronDevice, LutronKeypad
|
||||||
|
|
||||||
|
|
||||||
async def async_setup_entry(
|
async def async_setup_entry(
|
||||||
@ -33,11 +33,9 @@ async def async_setup_entry(
|
|||||||
entities.append(LutronSwitch(area_name, device, entry_data.client))
|
entities.append(LutronSwitch(area_name, device, entry_data.client))
|
||||||
|
|
||||||
# Add the indicator LEDs for scenes (keypad buttons)
|
# Add the indicator LEDs for scenes (keypad buttons)
|
||||||
for area_name, keypad_name, scene, led in entry_data.scenes:
|
for area_name, keypad, scene, led in entry_data.scenes:
|
||||||
if led is not None:
|
if led is not None:
|
||||||
entities.append(
|
entities.append(LutronLed(area_name, keypad, scene, led, entry_data.client))
|
||||||
LutronLed(area_name, keypad_name, scene, led, entry_data.client)
|
|
||||||
)
|
|
||||||
async_add_entities(entities, True)
|
async_add_entities(entities, True)
|
||||||
|
|
||||||
|
|
||||||
@ -77,7 +75,7 @@ class LutronSwitch(LutronDevice, SwitchEntity):
|
|||||||
self._prev_state = self._lutron_device.level > 0
|
self._prev_state = self._lutron_device.level > 0
|
||||||
|
|
||||||
|
|
||||||
class LutronLed(LutronDevice, SwitchEntity):
|
class LutronLed(LutronKeypad, SwitchEntity):
|
||||||
"""Representation of a Lutron Keypad LED."""
|
"""Representation of a Lutron Keypad LED."""
|
||||||
|
|
||||||
_lutron_device: Led
|
_lutron_device: Led
|
||||||
@ -85,15 +83,15 @@ class LutronLed(LutronDevice, SwitchEntity):
|
|||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
area_name: str,
|
area_name: str,
|
||||||
keypad_name: str,
|
keypad: Keypad,
|
||||||
scene_device: Button,
|
scene_device: Button,
|
||||||
led_device: Led,
|
led_device: Led,
|
||||||
controller: Lutron,
|
controller: Lutron,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Initialize the switch."""
|
"""Initialize the switch."""
|
||||||
self._keypad_name = keypad_name
|
super().__init__(area_name, led_device, controller, keypad)
|
||||||
self._scene_name = scene_device.name
|
self._keypad_name = keypad.name
|
||||||
super().__init__(area_name, led_device, controller)
|
self._attr_name = scene_device.name
|
||||||
|
|
||||||
def turn_on(self, **kwargs: Any) -> None:
|
def turn_on(self, **kwargs: Any) -> None:
|
||||||
"""Turn the LED on."""
|
"""Turn the LED on."""
|
||||||
@ -108,7 +106,7 @@ class LutronLed(LutronDevice, SwitchEntity):
|
|||||||
"""Return the state attributes."""
|
"""Return the state attributes."""
|
||||||
return {
|
return {
|
||||||
"keypad": self._keypad_name,
|
"keypad": self._keypad_name,
|
||||||
"scene": self._scene_name,
|
"scene": self._attr_name,
|
||||||
"led": self._lutron_device.name,
|
"led": self._lutron_device.name,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -117,11 +115,6 @@ class LutronLed(LutronDevice, SwitchEntity):
|
|||||||
"""Return true if device is on."""
|
"""Return true if device is on."""
|
||||||
return self._lutron_device.last_state
|
return self._lutron_device.last_state
|
||||||
|
|
||||||
@property
|
|
||||||
def name(self) -> str:
|
|
||||||
"""Return the name of the LED."""
|
|
||||||
return f"{self._area_name} {self._keypad_name}: {self._scene_name} LED"
|
|
||||||
|
|
||||||
def update(self) -> None:
|
def update(self) -> None:
|
||||||
"""Call when forcing a refresh of the device."""
|
"""Call when forcing a refresh of the device."""
|
||||||
# The following property getter actually triggers an update in Lutron
|
# The following property getter actually triggers an update in Lutron
|
||||||
|
Loading…
x
Reference in New Issue
Block a user