core/homeassistant/components/lutron/__init__.py

230 lines
7.6 KiB
Python
Raw Normal View History

"""Component for interacting with a Lutron RadioRA 2 system."""
import logging
from pylutron import Button, Lutron
import voluptuous as vol
from homeassistant import config_entries
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import (
ATTR_ID,
CONF_HOST,
CONF_PASSWORD,
CONF_USERNAME,
Platform,
)
from homeassistant.core import DOMAIN as HOMEASSISTANT_DOMAIN, HomeAssistant
from homeassistant.data_entry_flow import FlowResultType
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.issue_registry import IssueSeverity, async_create_issue
from homeassistant.helpers.typing import ConfigType
from homeassistant.util import slugify
from .const import DOMAIN
PLATFORMS = [
2024-01-05 16:31:50 +00:00
Platform.BINARY_SENSOR,
Platform.COVER,
2024-01-05 16:31:50 +00:00
Platform.LIGHT,
Platform.SCENE,
2024-01-05 16:31:50 +00:00
Platform.SWITCH,
]
_LOGGER = logging.getLogger(__name__)
2019-07-31 19:25:30 +00:00
LUTRON_BUTTONS = "lutron_buttons"
LUTRON_CONTROLLER = "lutron_controller"
LUTRON_DEVICES = "lutron_devices"
# Attribute on events that indicates what action was taken with the button.
2019-07-31 19:25:30 +00:00
ATTR_ACTION = "action"
ATTR_FULL_ID = "full_id"
ATTR_UUID = "uuid"
2019-07-31 19:25:30 +00:00
CONFIG_SCHEMA = vol.Schema(
{
DOMAIN: vol.Schema(
{
vol.Required(CONF_HOST): cv.string,
vol.Required(CONF_PASSWORD): cv.string,
vol.Required(CONF_USERNAME): cv.string,
}
)
},
extra=vol.ALLOW_EXTRA,
)
async def _async_import(hass: HomeAssistant, base_config: ConfigType) -> None:
"""Import a config entry from configuration.yaml."""
result = await hass.config_entries.flow.async_init(
DOMAIN,
context={"source": config_entries.SOURCE_IMPORT},
data=base_config[DOMAIN],
)
if (
result["type"] == FlowResultType.CREATE_ENTRY
or result["reason"] == "single_instance_allowed"
):
async_create_issue(
hass,
HOMEASSISTANT_DOMAIN,
f"deprecated_yaml_{DOMAIN}",
breaks_in_ha_version="2024.7.0",
is_fixable=False,
issue_domain=DOMAIN,
severity=IssueSeverity.WARNING,
translation_key="deprecated_yaml",
translation_placeholders={
"domain": DOMAIN,
"integration_title": "Lutron",
},
)
return
async_create_issue(
hass,
DOMAIN,
f"deprecated_yaml_import_issue_{result['reason']}",
breaks_in_ha_version="2024.7.0",
is_fixable=False,
issue_domain=DOMAIN,
severity=IssueSeverity.WARNING,
translation_key=f"deprecated_yaml_import_issue_{result['reason']}",
translation_placeholders={
"domain": DOMAIN,
"integration_title": "Lutron",
},
)
async def async_setup(hass: HomeAssistant, base_config: ConfigType) -> bool:
"""Set up the Lutron component."""
if DOMAIN in base_config:
hass.async_create_task(_async_import(hass, base_config))
return True
async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> bool:
"""Set up the Lutron integration."""
hass.data.setdefault(DOMAIN, {})
hass.data[LUTRON_BUTTONS] = []
hass.data[LUTRON_CONTROLLER] = None
hass.data[LUTRON_DEVICES] = {
"light": [],
"cover": [],
"switch": [],
"scene": [],
"binary_sensor": [],
}
host = config_entry.data[CONF_HOST]
uid = config_entry.data[CONF_USERNAME]
pwd = config_entry.data[CONF_PASSWORD]
def _load_db() -> bool:
hass.data[LUTRON_CONTROLLER].load_xml_db()
return True
hass.data[LUTRON_CONTROLLER] = Lutron(host, uid, pwd)
await hass.async_add_executor_job(_load_db)
hass.data[LUTRON_CONTROLLER].connect()
_LOGGER.info("Connected to main repeater at %s", host)
# Sort our devices into types
_LOGGER.debug("Start adding devices")
for area in hass.data[LUTRON_CONTROLLER].areas:
_LOGGER.debug("Working on area %s", area.name)
for output in area.outputs:
_LOGGER.debug("Working on output %s", output.type)
2019-07-31 19:25:30 +00:00
if output.type == "SYSTEM_SHADE":
hass.data[LUTRON_DEVICES]["cover"].append((area.name, output))
elif output.is_dimmable:
2019-07-31 19:25:30 +00:00
hass.data[LUTRON_DEVICES]["light"].append((area.name, output))
else:
2019-07-31 19:25:30 +00:00
hass.data[LUTRON_DEVICES]["switch"].append((area.name, output))
for keypad in area.keypads:
for button in keypad.buttons:
# If the button has a function assigned to it, add it as a scene
if button.name != "Unknown Button" and button.button_type in (
"SingleAction",
"Toggle",
"SingleSceneRaiseLower",
"MasterRaiseLower",
):
# Associate an LED with a button if there is one
led = next(
(led for led in keypad.leds if led.number == button.number),
None,
)
hass.data[LUTRON_DEVICES]["scene"].append(
(area.name, keypad.name, button, led)
)
2019-07-31 19:25:30 +00:00
hass.data[LUTRON_BUTTONS].append(
LutronButton(hass, area.name, keypad, button)
)
if area.occupancy_group is not None:
hass.data[LUTRON_DEVICES]["binary_sensor"].append(
(area.name, area.occupancy_group)
)
await hass.config_entries.async_forward_entry_setups(config_entry, PLATFORMS)
2019-07-31 19:25:30 +00:00
return True
async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Clean up resources and entities associated with the integration."""
return await hass.config_entries.async_unload_platforms(entry, PLATFORMS)
class LutronButton:
"""Representation of a button on a Lutron keypad.
This is responsible for firing events as keypad buttons are pressed
(and possibly released, depending on the button type). It is not
represented as an entity; it simply fires events.
"""
def __init__(self, hass: HomeAssistant, area_name, keypad, button) -> None:
"""Register callback for activity on the button."""
name = f"{keypad.name}: {button.name}"
if button.name == "Unknown Button":
name += f" {button.number}"
self._hass = hass
2019-07-31 19:25:30 +00:00
self._has_release_event = (
button.button_type is not None and "RaiseLower" in button.button_type
)
self._id = slugify(name)
self._keypad = keypad
self._area_name = area_name
self._button_name = button.name
self._button = button
2019-07-31 19:25:30 +00:00
self._event = "lutron_event"
self._full_id = slugify(f"{area_name} {name}")
self._uuid = button.uuid
button.subscribe(self.button_callback, None)
def button_callback(self, button, context, event, params):
"""Fire an event about a button being pressed or released."""
# Events per button type:
# RaiseLower -> pressed/released
# SingleAction -> single
action = None
if self._has_release_event:
if event == Button.Event.PRESSED:
2019-07-31 19:25:30 +00:00
action = "pressed"
else:
2019-07-31 19:25:30 +00:00
action = "released"
elif event == Button.Event.PRESSED:
2019-07-31 19:25:30 +00:00
action = "single"
if action:
data = {
ATTR_ID: self._id,
ATTR_ACTION: action,
ATTR_FULL_ID: self._full_id,
ATTR_UUID: self._uuid,
}
self._hass.bus.fire(self._event, data)