Add pico remote support to non-pro lutron caseta bridges (#61032)
parent
832184bacd
commit
e834382b9a
|
@ -1,19 +1,19 @@
|
|||
"""Component for interacting with a Lutron Caseta system."""
|
||||
from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
import contextlib
|
||||
import logging
|
||||
import ssl
|
||||
|
||||
from aiolip import LIP
|
||||
from aiolip.data import LIPMode
|
||||
from aiolip.protocol import LIP_BUTTON_PRESS
|
||||
import async_timeout
|
||||
from pylutron_caseta import BUTTON_STATUS_PRESSED
|
||||
from pylutron_caseta.smartbridge import Smartbridge
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant import config_entries
|
||||
from homeassistant.const import CONF_HOST, Platform
|
||||
from homeassistant.core import callback
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.exceptions import ConfigEntryNotReady
|
||||
from homeassistant.helpers import device_registry as dr
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
|
@ -26,12 +26,12 @@ from .const import (
|
|||
ATTR_AREA_NAME,
|
||||
ATTR_BUTTON_NUMBER,
|
||||
ATTR_DEVICE_NAME,
|
||||
ATTR_LEAP_BUTTON_NUMBER,
|
||||
ATTR_SERIAL,
|
||||
ATTR_TYPE,
|
||||
BRIDGE_DEVICE,
|
||||
BRIDGE_DEVICE_ID,
|
||||
BRIDGE_LEAP,
|
||||
BRIDGE_LIP,
|
||||
BRIDGE_TIMEOUT,
|
||||
BUTTON_DEVICES,
|
||||
CONF_CA_CERTS,
|
||||
|
@ -41,6 +41,10 @@ from .const import (
|
|||
LUTRON_CASETA_BUTTON_EVENT,
|
||||
MANUFACTURER,
|
||||
)
|
||||
from .device_trigger import (
|
||||
DEVICE_TYPE_SUBTYPE_MAP_TO_LIP,
|
||||
LEAP_TO_DEVICE_TYPE_SUBTYPE_MAP,
|
||||
)
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
@ -97,8 +101,11 @@ async def async_setup(hass, base_config):
|
|||
return True
|
||||
|
||||
|
||||
async def async_setup_entry(hass, config_entry):
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant, config_entry: config_entries.ConfigEntry
|
||||
) -> bool:
|
||||
"""Set up a bridge from a config entry."""
|
||||
entry_id = config_entry.entry_id
|
||||
host = config_entry.data[CONF_HOST]
|
||||
keyfile = hass.config.path(config_entry.data[CONF_KEYFILE])
|
||||
certfile = hass.config.path(config_entry.data[CONF_CERTFILE])
|
||||
|
@ -130,85 +137,30 @@ async def async_setup_entry(hass, config_entry):
|
|||
|
||||
devices = bridge.get_devices()
|
||||
bridge_device = devices[BRIDGE_DEVICE_ID]
|
||||
_async_register_bridge_device(hass, config_entry.entry_id, bridge_device)
|
||||
buttons = bridge.buttons
|
||||
_async_register_bridge_device(hass, entry_id, bridge_device)
|
||||
button_devices = _async_register_button_devices(
|
||||
hass, entry_id, bridge_device, buttons
|
||||
)
|
||||
_async_subscribe_pico_remote_events(hass, bridge, buttons)
|
||||
|
||||
# Store this bridge (keyed by entry_id) so it can be retrieved by the
|
||||
# platforms we're setting up.
|
||||
hass.data[DOMAIN][config_entry.entry_id] = {
|
||||
hass.data[DOMAIN][entry_id] = {
|
||||
BRIDGE_LEAP: bridge,
|
||||
BRIDGE_DEVICE: bridge_device,
|
||||
BUTTON_DEVICES: {},
|
||||
BRIDGE_LIP: None,
|
||||
BUTTON_DEVICES: button_devices,
|
||||
}
|
||||
|
||||
if bridge.lip_devices:
|
||||
# If the bridge also supports LIP (Lutron Integration Protocol)
|
||||
# we can fire events when pico buttons are pressed to allow
|
||||
# pico remotes to control other devices.
|
||||
await async_setup_lip(hass, config_entry, bridge.lip_devices)
|
||||
|
||||
hass.config_entries.async_setup_platforms(config_entry, PLATFORMS)
|
||||
|
||||
return True
|
||||
|
||||
|
||||
async def async_setup_lip(hass, config_entry, lip_devices):
|
||||
"""Connect to the bridge via Lutron Integration Protocol to watch for pico remotes."""
|
||||
host = config_entry.data[CONF_HOST]
|
||||
config_entry_id = config_entry.entry_id
|
||||
data = hass.data[DOMAIN][config_entry_id]
|
||||
bridge_device = data[BRIDGE_DEVICE]
|
||||
bridge = data[BRIDGE_LEAP]
|
||||
lip = LIP()
|
||||
try:
|
||||
await lip.async_connect(host)
|
||||
except asyncio.TimeoutError:
|
||||
_LOGGER.warning(
|
||||
"Failed to connect to via LIP at %s:23, Pico and Shade remotes will not be available; "
|
||||
"Enable Telnet Support in the Lutron app under Settings >> Advanced >> Integration",
|
||||
host,
|
||||
)
|
||||
return
|
||||
|
||||
_LOGGER.debug("Connected to Lutron Caseta bridge via LIP at %s:23", host)
|
||||
button_devices_by_lip_id = _async_merge_lip_leap_data(lip_devices, bridge)
|
||||
button_devices_by_dr_id = _async_register_button_devices(
|
||||
hass, config_entry_id, bridge_device, button_devices_by_lip_id
|
||||
)
|
||||
_async_subscribe_pico_remote_events(hass, lip, button_devices_by_lip_id)
|
||||
data[BUTTON_DEVICES] = button_devices_by_dr_id
|
||||
data[BRIDGE_LIP] = lip
|
||||
|
||||
|
||||
@callback
|
||||
def _async_merge_lip_leap_data(lip_devices, bridge):
|
||||
"""Merge the leap data into the lip data."""
|
||||
sensor_devices = bridge.get_devices_by_domain("sensor")
|
||||
|
||||
button_devices_by_id = {
|
||||
id: device for id, device in lip_devices.items() if "Buttons" in device
|
||||
}
|
||||
sensor_devices_by_name = {device["name"]: device for device in sensor_devices}
|
||||
|
||||
# Add the leap data into the lip data
|
||||
# so we know the type, model, and serial
|
||||
for device in button_devices_by_id.values():
|
||||
area = device.get("Area", {}).get("Name", "")
|
||||
name = device["Name"]
|
||||
leap_name = f"{area}_{name}"
|
||||
device["leap_name"] = leap_name
|
||||
leap_device_data = sensor_devices_by_name.get(leap_name)
|
||||
if leap_device_data is None:
|
||||
continue
|
||||
for key in ("type", "model", "serial"):
|
||||
if (val := leap_device_data.get(key)) is not None:
|
||||
device[key] = val
|
||||
|
||||
_LOGGER.debug("Button Devices: %s", button_devices_by_id)
|
||||
return button_devices_by_id
|
||||
|
||||
|
||||
@callback
|
||||
def _async_register_bridge_device(hass, config_entry_id, bridge_device):
|
||||
def _async_register_bridge_device(
|
||||
hass: HomeAssistant, config_entry_id: str, bridge_device: dict
|
||||
) -> None:
|
||||
"""Register the bridge device in the device registry."""
|
||||
device_registry = dr.async_get(hass)
|
||||
device_registry.async_get_or_create(
|
||||
|
@ -217,24 +169,30 @@ def _async_register_bridge_device(hass, config_entry_id, bridge_device):
|
|||
config_entry_id=config_entry_id,
|
||||
identifiers={(DOMAIN, bridge_device["serial"])},
|
||||
model=f"{bridge_device['model']} ({bridge_device['type']})",
|
||||
configuration_url="https://device-login.lutron.com",
|
||||
)
|
||||
|
||||
|
||||
@callback
|
||||
def _async_register_button_devices(
|
||||
hass, config_entry_id, bridge_device, button_devices_by_id
|
||||
):
|
||||
hass: HomeAssistant,
|
||||
config_entry_id: str,
|
||||
bridge_device,
|
||||
button_devices_by_id: dict[int, dict],
|
||||
) -> dict[str, dr.DeviceEntry]:
|
||||
"""Register button devices (Pico Remotes) in the device registry."""
|
||||
device_registry = dr.async_get(hass)
|
||||
button_devices_by_dr_id = {}
|
||||
seen = set()
|
||||
|
||||
for device in button_devices_by_id.values():
|
||||
if "serial" not in device:
|
||||
if "serial" not in device or device["serial"] in seen:
|
||||
continue
|
||||
seen.add(device["serial"])
|
||||
|
||||
dr_device = device_registry.async_get_or_create(
|
||||
name=device["leap_name"],
|
||||
suggested_area=device["leap_name"].split("_")[0],
|
||||
name=device["name"],
|
||||
suggested_area=device["name"].split("_")[0],
|
||||
manufacturer=MANUFACTURER,
|
||||
config_entry_id=config_entry_id,
|
||||
identifiers={(DOMAIN, device["serial"])},
|
||||
|
@ -248,54 +206,74 @@ def _async_register_button_devices(
|
|||
|
||||
|
||||
@callback
|
||||
def _async_subscribe_pico_remote_events(hass, lip, button_devices_by_id):
|
||||
def _async_subscribe_pico_remote_events(
|
||||
hass: HomeAssistant,
|
||||
bridge_device: Smartbridge,
|
||||
button_devices_by_id: dict[int, dict],
|
||||
):
|
||||
"""Subscribe to lutron events."""
|
||||
|
||||
@callback
|
||||
def _async_lip_event(lip_message):
|
||||
if lip_message.mode != LIPMode.DEVICE:
|
||||
return
|
||||
|
||||
device = button_devices_by_id.get(lip_message.integration_id)
|
||||
def _async_button_event(button_id, event_type):
|
||||
device = button_devices_by_id.get(button_id)
|
||||
|
||||
if not device:
|
||||
return
|
||||
|
||||
if lip_message.value == LIP_BUTTON_PRESS:
|
||||
if event_type == BUTTON_STATUS_PRESSED:
|
||||
action = ACTION_PRESS
|
||||
else:
|
||||
action = ACTION_RELEASE
|
||||
|
||||
type_ = device["type"]
|
||||
name = device["name"]
|
||||
button_number = device["button_number"]
|
||||
# The original implementation used LIP instead of LEAP
|
||||
# so we need to convert the button number to maintain compat
|
||||
sub_type_to_lip_button = DEVICE_TYPE_SUBTYPE_MAP_TO_LIP[type_]
|
||||
leap_button_to_sub_type = LEAP_TO_DEVICE_TYPE_SUBTYPE_MAP[type_]
|
||||
if (sub_type := leap_button_to_sub_type.get(button_number)) is None:
|
||||
_LOGGER.error(
|
||||
"Unknown LEAP button number %s is not in %s for %s (%s)",
|
||||
button_number,
|
||||
leap_button_to_sub_type,
|
||||
name,
|
||||
type_,
|
||||
)
|
||||
return
|
||||
lip_button_number = sub_type_to_lip_button[sub_type]
|
||||
|
||||
hass.bus.async_fire(
|
||||
LUTRON_CASETA_BUTTON_EVENT,
|
||||
{
|
||||
ATTR_SERIAL: device.get("serial"),
|
||||
ATTR_TYPE: device.get("type"),
|
||||
ATTR_BUTTON_NUMBER: lip_message.action_number,
|
||||
ATTR_DEVICE_NAME: device["Name"],
|
||||
ATTR_AREA_NAME: device.get("Area", {}).get("Name"),
|
||||
ATTR_SERIAL: device["serial"],
|
||||
ATTR_TYPE: type_,
|
||||
ATTR_BUTTON_NUMBER: lip_button_number,
|
||||
ATTR_LEAP_BUTTON_NUMBER: button_number,
|
||||
ATTR_DEVICE_NAME: name,
|
||||
ATTR_AREA_NAME: name.split("_")[0],
|
||||
ATTR_ACTION: action,
|
||||
},
|
||||
)
|
||||
|
||||
lip.subscribe(_async_lip_event)
|
||||
|
||||
asyncio.create_task(lip.async_run())
|
||||
for button_id in button_devices_by_id:
|
||||
bridge_device.add_button_subscriber(
|
||||
str(button_id),
|
||||
lambda event_type, button_id=button_id: _async_button_event(
|
||||
button_id, event_type
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
async def async_unload_entry(hass, config_entry):
|
||||
async def async_unload_entry(
|
||||
hass: HomeAssistant, entry: config_entries.ConfigEntry
|
||||
) -> bool:
|
||||
"""Unload the bridge bridge from a config entry."""
|
||||
data = hass.data[DOMAIN][config_entry.entry_id]
|
||||
data[BRIDGE_LEAP].close()
|
||||
if data[BRIDGE_LIP]:
|
||||
await data[BRIDGE_LIP].async_stop()
|
||||
|
||||
unload_ok = await hass.config_entries.async_unload_platforms(
|
||||
config_entry, PLATFORMS
|
||||
)
|
||||
if unload_ok:
|
||||
hass.data[DOMAIN].pop(config_entry.entry_id)
|
||||
|
||||
data = hass.data[DOMAIN][entry.entry_id]
|
||||
smartbridge: Smartbridge = data[BRIDGE_LEAP]
|
||||
await smartbridge.close()
|
||||
if unload_ok := await hass.config_entries.async_unload_platforms(entry, PLATFORMS):
|
||||
hass.data[DOMAIN].pop(entry.entry_id)
|
||||
return unload_ok
|
||||
|
||||
|
||||
|
|
|
@ -11,7 +11,6 @@ ERROR_CANNOT_CONNECT = "cannot_connect"
|
|||
ABORT_REASON_CANNOT_CONNECT = "cannot_connect"
|
||||
|
||||
BRIDGE_LEAP = "leap"
|
||||
BRIDGE_LIP = "lip"
|
||||
BRIDGE_DEVICE = "bridge_device"
|
||||
BUTTON_DEVICES = "button_devices"
|
||||
LUTRON_CASETA_BUTTON_EVENT = "lutron_caseta_button_event"
|
||||
|
@ -22,7 +21,8 @@ MANUFACTURER = "Lutron Electronics Co., Inc"
|
|||
|
||||
ATTR_SERIAL = "serial"
|
||||
ATTR_TYPE = "type"
|
||||
ATTR_BUTTON_NUMBER = "button_number"
|
||||
ATTR_LEAP_BUTTON_NUMBER = "leap_button_number"
|
||||
ATTR_BUTTON_NUMBER = "button_number" # LIP button number
|
||||
ATTR_DEVICE_NAME = "device_name"
|
||||
ATTR_AREA_NAME = "area_name"
|
||||
ATTR_ACTION = "action"
|
||||
|
|
|
@ -46,106 +46,180 @@ LUTRON_BUTTON_TRIGGER_SCHEMA = DEVICE_TRIGGER_BASE_SCHEMA.extend(
|
|||
)
|
||||
|
||||
|
||||
PICO_2_BUTTON_BUTTON_TYPES = {
|
||||
PICO_2_BUTTON_BUTTON_TYPES_TO_LIP = {
|
||||
"on": 2,
|
||||
"off": 4,
|
||||
}
|
||||
PICO_2_BUTTON_BUTTON_TYPES_TO_LEAP = {
|
||||
"on": 0,
|
||||
"off": 2,
|
||||
}
|
||||
LEAP_TO_PICO_2_BUTTON_BUTTON_TYPES = {
|
||||
v: k for k, v in PICO_2_BUTTON_BUTTON_TYPES_TO_LEAP.items()
|
||||
}
|
||||
PICO_2_BUTTON_TRIGGER_SCHEMA = LUTRON_BUTTON_TRIGGER_SCHEMA.extend(
|
||||
{
|
||||
vol.Required(CONF_SUBTYPE): vol.In(PICO_2_BUTTON_BUTTON_TYPES),
|
||||
vol.Required(CONF_SUBTYPE): vol.In(PICO_2_BUTTON_BUTTON_TYPES_TO_LIP),
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
PICO_2_BUTTON_RAISE_LOWER_BUTTON_TYPES = {
|
||||
PICO_2_BUTTON_RAISE_LOWER_BUTTON_TYPES_TO_LIP = {
|
||||
"on": 2,
|
||||
"off": 4,
|
||||
"raise": 5,
|
||||
"lower": 6,
|
||||
}
|
||||
PICO_2_BUTTON_RAISE_LOWER_BUTTON_TYPES_TO_LEAP = {
|
||||
"on": 0,
|
||||
"off": 2,
|
||||
"raise": 3,
|
||||
"lower": 4,
|
||||
}
|
||||
LEAP_TO_PICO_2_BUTTON_RAISE_LOWER_BUTTON_TYPES = {
|
||||
v: k for k, v in PICO_2_BUTTON_RAISE_LOWER_BUTTON_TYPES_TO_LEAP.items()
|
||||
}
|
||||
PICO_2_BUTTON_RAISE_LOWER_TRIGGER_SCHEMA = LUTRON_BUTTON_TRIGGER_SCHEMA.extend(
|
||||
{
|
||||
vol.Required(CONF_SUBTYPE): vol.In(PICO_2_BUTTON_RAISE_LOWER_BUTTON_TYPES),
|
||||
vol.Required(CONF_SUBTYPE): vol.In(
|
||||
PICO_2_BUTTON_RAISE_LOWER_BUTTON_TYPES_TO_LIP
|
||||
),
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
PICO_3_BUTTON_BUTTON_TYPES = {
|
||||
PICO_3_BUTTON_BUTTON_TYPES_TO_LIP = {
|
||||
"on": 2,
|
||||
"stop": 3,
|
||||
"off": 4,
|
||||
}
|
||||
PICO_3_BUTTON_BUTTON_TYPES_TO_LEAP = {
|
||||
"on": 0,
|
||||
"stop": 1,
|
||||
"off": 2,
|
||||
}
|
||||
LEAP_TO_PICO_3_BUTTON_BUTTON_TYPES = {
|
||||
v: k for k, v in PICO_3_BUTTON_BUTTON_TYPES_TO_LEAP.items()
|
||||
}
|
||||
PICO_3_BUTTON_TRIGGER_SCHEMA = LUTRON_BUTTON_TRIGGER_SCHEMA.extend(
|
||||
{
|
||||
vol.Required(CONF_SUBTYPE): vol.In(PICO_3_BUTTON_BUTTON_TYPES),
|
||||
vol.Required(CONF_SUBTYPE): vol.In(PICO_3_BUTTON_BUTTON_TYPES_TO_LIP),
|
||||
}
|
||||
)
|
||||
|
||||
PICO_3_BUTTON_RAISE_LOWER_BUTTON_TYPES = {
|
||||
PICO_3_BUTTON_RAISE_LOWER_BUTTON_TYPES_TO_LIP = {
|
||||
"on": 2,
|
||||
"stop": 3,
|
||||
"off": 4,
|
||||
"raise": 5,
|
||||
"lower": 6,
|
||||
}
|
||||
PICO_3_BUTTON_RAISE_LOWER_BUTTON_TYPES_TO_LEAP = {
|
||||
"on": 0,
|
||||
"stop": 1,
|
||||
"off": 2,
|
||||
"raise": 3,
|
||||
"lower": 4,
|
||||
}
|
||||
LEAP_TO_PICO_3_BUTTON_RAISE_LOWER_BUTTON_TYPES = {
|
||||
v: k for k, v in PICO_3_BUTTON_RAISE_LOWER_BUTTON_TYPES_TO_LEAP.items()
|
||||
}
|
||||
PICO_3_BUTTON_RAISE_LOWER_TRIGGER_SCHEMA = LUTRON_BUTTON_TRIGGER_SCHEMA.extend(
|
||||
{
|
||||
vol.Required(CONF_SUBTYPE): vol.In(PICO_3_BUTTON_RAISE_LOWER_BUTTON_TYPES),
|
||||
vol.Required(CONF_SUBTYPE): vol.In(
|
||||
PICO_3_BUTTON_RAISE_LOWER_BUTTON_TYPES_TO_LIP
|
||||
),
|
||||
}
|
||||
)
|
||||
|
||||
PICO_4_BUTTON_BUTTON_TYPES = {
|
||||
PICO_4_BUTTON_BUTTON_TYPES_TO_LIP = {
|
||||
"button_1": 8,
|
||||
"button_2": 9,
|
||||
"button_3": 10,
|
||||
"button_4": 11,
|
||||
}
|
||||
PICO_4_BUTTON_BUTTON_TYPES_TO_LEAP = {
|
||||
"button_1": 1,
|
||||
"button_2": 2,
|
||||
"button_3": 3,
|
||||
"button_4": 4,
|
||||
}
|
||||
LEAP_TO_PICO_4_BUTTON_BUTTON_TYPES = {
|
||||
v: k for k, v in PICO_4_BUTTON_BUTTON_TYPES_TO_LEAP.items()
|
||||
}
|
||||
PICO_4_BUTTON_TRIGGER_SCHEMA = LUTRON_BUTTON_TRIGGER_SCHEMA.extend(
|
||||
{
|
||||
vol.Required(CONF_SUBTYPE): vol.In(PICO_4_BUTTON_BUTTON_TYPES),
|
||||
vol.Required(CONF_SUBTYPE): vol.In(PICO_4_BUTTON_BUTTON_TYPES_TO_LIP),
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
PICO_4_BUTTON_ZONE_BUTTON_TYPES = {
|
||||
PICO_4_BUTTON_ZONE_BUTTON_TYPES_TO_LIP = {
|
||||
"on": 8,
|
||||
"raise": 9,
|
||||
"lower": 10,
|
||||
"off": 11,
|
||||
}
|
||||
PICO_4_BUTTON_ZONE_BUTTON_TYPES_TO_LEAP = {
|
||||
"on": 1,
|
||||
"raise": 2,
|
||||
"lower": 3,
|
||||
"off": 4,
|
||||
}
|
||||
LEAP_TO_PICO_4_BUTTON_ZONE_BUTTON_TYPES = {
|
||||
v: k for k, v in PICO_4_BUTTON_ZONE_BUTTON_TYPES_TO_LEAP.items()
|
||||
}
|
||||
PICO_4_BUTTON_ZONE_TRIGGER_SCHEMA = LUTRON_BUTTON_TRIGGER_SCHEMA.extend(
|
||||
{
|
||||
vol.Required(CONF_SUBTYPE): vol.In(PICO_4_BUTTON_ZONE_BUTTON_TYPES),
|
||||
vol.Required(CONF_SUBTYPE): vol.In(PICO_4_BUTTON_ZONE_BUTTON_TYPES_TO_LIP),
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
PICO_4_BUTTON_SCENE_BUTTON_TYPES = {
|
||||
PICO_4_BUTTON_SCENE_BUTTON_TYPES_TO_LIP = {
|
||||
"button_1": 8,
|
||||
"button_2": 9,
|
||||
"button_3": 10,
|
||||
"off": 11,
|
||||
}
|
||||
PICO_4_BUTTON_SCENE_BUTTON_TYPES_TO_LEAP = {
|
||||
"button_1": 1,
|
||||
"button_2": 2,
|
||||
"button_3": 3,
|
||||
"off": 4,
|
||||
}
|
||||
LEAP_TO_PICO_4_BUTTON_SCENE_BUTTON_TYPES = {
|
||||
v: k for k, v in PICO_4_BUTTON_SCENE_BUTTON_TYPES_TO_LEAP.items()
|
||||
}
|
||||
PICO_4_BUTTON_SCENE_TRIGGER_SCHEMA = LUTRON_BUTTON_TRIGGER_SCHEMA.extend(
|
||||
{
|
||||
vol.Required(CONF_SUBTYPE): vol.In(PICO_4_BUTTON_SCENE_BUTTON_TYPES),
|
||||
vol.Required(CONF_SUBTYPE): vol.In(PICO_4_BUTTON_SCENE_BUTTON_TYPES_TO_LIP),
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
PICO_4_BUTTON_2_GROUP_BUTTON_TYPES = {
|
||||
PICO_4_BUTTON_2_GROUP_BUTTON_TYPES_TO_LIP = {
|
||||
"group_1_button_1": 8,
|
||||
"group_1_button_2": 9,
|
||||
"group_2_button_1": 10,
|
||||
"group_2_button_2": 11,
|
||||
}
|
||||
PICO_4_BUTTON_2_GROUP_BUTTON_TYPES_TO_LEAP = {
|
||||
"group_1_button_1": 1,
|
||||
"group_1_button_2": 2,
|
||||
"group_2_button_1": 3,
|
||||
"group_2_button_2": 4,
|
||||
}
|
||||
LEAP_TO_PICO_4_BUTTON_2_GROUP_BUTTON_TYPES = {
|
||||
v: k for k, v in PICO_4_BUTTON_2_GROUP_BUTTON_TYPES_TO_LEAP.items()
|
||||
}
|
||||
PICO_4_BUTTON_2_GROUP_TRIGGER_SCHEMA = LUTRON_BUTTON_TRIGGER_SCHEMA.extend(
|
||||
{
|
||||
vol.Required(CONF_SUBTYPE): vol.In(PICO_4_BUTTON_2_GROUP_BUTTON_TYPES),
|
||||
vol.Required(CONF_SUBTYPE): vol.In(PICO_4_BUTTON_2_GROUP_BUTTON_TYPES_TO_LIP),
|
||||
}
|
||||
)
|
||||
|
||||
FOUR_GROUP_REMOTE_BUTTON_TYPES = {
|
||||
FOUR_GROUP_REMOTE_BUTTON_TYPES_TO_LIP = {
|
||||
"open_all": 2,
|
||||
"stop_all": 3,
|
||||
"close_all": 4,
|
||||
|
@ -172,9 +246,39 @@ FOUR_GROUP_REMOTE_BUTTON_TYPES = {
|
|||
"raise_4": 37,
|
||||
"lower_4": 38,
|
||||
}
|
||||
FOUR_GROUP_REMOTE_BUTTON_TYPES_TO_LEAP = {
|
||||
"open_all": 0,
|
||||
"stop_all": 1,
|
||||
"close_all": 2,
|
||||
"raise_all": 3,
|
||||
"lower_all": 4,
|
||||
"open_1": 5,
|
||||
"stop_1": 6,
|
||||
"close_1": 7,
|
||||
"raise_1": 8,
|
||||
"lower_1": 9,
|
||||
"open_2": 10,
|
||||
"stop_2": 11,
|
||||
"close_2": 12,
|
||||
"raise_2": 13,
|
||||
"lower_2": 14,
|
||||
"open_3": 15,
|
||||
"stop_3": 16,
|
||||
"close_3": 17,
|
||||
"raise_3": 18,
|
||||
"lower_3": 19,
|
||||
"open_4": 20,
|
||||
"stop_4": 21,
|
||||
"close_4": 22,
|
||||
"raise_4": 23,
|
||||
"lower_4": 24,
|
||||
}
|
||||
LEAP_TO_FOUR_GROUP_REMOTE_BUTTON_TYPES = {
|
||||
v: k for k, v in FOUR_GROUP_REMOTE_BUTTON_TYPES_TO_LEAP.items()
|
||||
}
|
||||
FOUR_GROUP_REMOTE_TRIGGER_SCHEMA = LUTRON_BUTTON_TRIGGER_SCHEMA.extend(
|
||||
{
|
||||
vol.Required(CONF_SUBTYPE): vol.In(FOUR_GROUP_REMOTE_BUTTON_TYPES),
|
||||
vol.Required(CONF_SUBTYPE): vol.In(FOUR_GROUP_REMOTE_BUTTON_TYPES_TO_LIP),
|
||||
}
|
||||
)
|
||||
|
||||
|
@ -190,16 +294,28 @@ DEVICE_TYPE_SCHEMA_MAP = {
|
|||
"FourGroupRemote": FOUR_GROUP_REMOTE_TRIGGER_SCHEMA,
|
||||
}
|
||||
|
||||
DEVICE_TYPE_SUBTYPE_MAP = {
|
||||
"Pico2Button": PICO_2_BUTTON_BUTTON_TYPES,
|
||||
"Pico2ButtonRaiseLower": PICO_2_BUTTON_RAISE_LOWER_BUTTON_TYPES,
|
||||
"Pico3Button": PICO_3_BUTTON_BUTTON_TYPES,
|
||||
"Pico3ButtonRaiseLower": PICO_3_BUTTON_RAISE_LOWER_BUTTON_TYPES,
|
||||
"Pico4Button": PICO_4_BUTTON_BUTTON_TYPES,
|
||||
"Pico4ButtonScene": PICO_4_BUTTON_SCENE_BUTTON_TYPES,
|
||||
"Pico4ButtonZone": PICO_4_BUTTON_ZONE_BUTTON_TYPES,
|
||||
"Pico4Button2Group": PICO_4_BUTTON_2_GROUP_BUTTON_TYPES,
|
||||
"FourGroupRemote": FOUR_GROUP_REMOTE_BUTTON_TYPES,
|
||||
DEVICE_TYPE_SUBTYPE_MAP_TO_LIP = {
|
||||
"Pico2Button": PICO_2_BUTTON_BUTTON_TYPES_TO_LIP,
|
||||
"Pico2ButtonRaiseLower": PICO_2_BUTTON_RAISE_LOWER_BUTTON_TYPES_TO_LIP,
|
||||
"Pico3Button": PICO_3_BUTTON_BUTTON_TYPES_TO_LIP,
|
||||
"Pico3ButtonRaiseLower": PICO_3_BUTTON_RAISE_LOWER_BUTTON_TYPES_TO_LIP,
|
||||
"Pico4Button": PICO_4_BUTTON_BUTTON_TYPES_TO_LIP,
|
||||
"Pico4ButtonScene": PICO_4_BUTTON_SCENE_BUTTON_TYPES_TO_LIP,
|
||||
"Pico4ButtonZone": PICO_4_BUTTON_ZONE_BUTTON_TYPES_TO_LIP,
|
||||
"Pico4Button2Group": PICO_4_BUTTON_2_GROUP_BUTTON_TYPES_TO_LIP,
|
||||
"FourGroupRemote": FOUR_GROUP_REMOTE_BUTTON_TYPES_TO_LIP,
|
||||
}
|
||||
|
||||
LEAP_TO_DEVICE_TYPE_SUBTYPE_MAP = {
|
||||
"Pico2Button": LEAP_TO_PICO_2_BUTTON_BUTTON_TYPES,
|
||||
"Pico2ButtonRaiseLower": LEAP_TO_PICO_2_BUTTON_RAISE_LOWER_BUTTON_TYPES,
|
||||
"Pico3Button": LEAP_TO_PICO_3_BUTTON_BUTTON_TYPES,
|
||||
"Pico3ButtonRaiseLower": LEAP_TO_PICO_3_BUTTON_RAISE_LOWER_BUTTON_TYPES,
|
||||
"Pico4Button": LEAP_TO_PICO_4_BUTTON_BUTTON_TYPES,
|
||||
"Pico4ButtonScene": LEAP_TO_PICO_4_BUTTON_SCENE_BUTTON_TYPES,
|
||||
"Pico4ButtonZone": LEAP_TO_PICO_4_BUTTON_ZONE_BUTTON_TYPES,
|
||||
"Pico4Button2Group": LEAP_TO_PICO_4_BUTTON_2_GROUP_BUTTON_TYPES,
|
||||
"FourGroupRemote": LEAP_TO_FOUR_GROUP_REMOTE_BUTTON_TYPES,
|
||||
}
|
||||
|
||||
TRIGGER_SCHEMA = vol.Any(
|
||||
|
@ -238,7 +354,7 @@ async def async_get_triggers(
|
|||
if not (device := get_button_device_by_dr_id(hass, device_id)):
|
||||
raise InvalidDeviceAutomationConfig(f"Device not found: {device_id}")
|
||||
|
||||
valid_buttons = DEVICE_TYPE_SUBTYPE_MAP.get(device["type"], [])
|
||||
valid_buttons = DEVICE_TYPE_SUBTYPE_MAP_TO_LIP.get(device["type"], [])
|
||||
|
||||
for trigger in SUPPORTED_INPUTS_EVENTS_TYPES:
|
||||
for subtype in valid_buttons:
|
||||
|
@ -273,7 +389,7 @@ async def async_attach_trigger(
|
|||
device_type = _device_model_to_type(device.model)
|
||||
_, serial = list(device.identifiers)[0]
|
||||
schema = DEVICE_TYPE_SCHEMA_MAP.get(device_type)
|
||||
valid_buttons = DEVICE_TYPE_SUBTYPE_MAP.get(device_type)
|
||||
valid_buttons = DEVICE_TYPE_SUBTYPE_MAP_TO_LIP.get(device_type)
|
||||
config = schema(config)
|
||||
event_config = {
|
||||
event_trigger.CONF_PLATFORM: CONF_EVENT,
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
"domain": "lutron_caseta",
|
||||
"name": "Lutron Cas\u00e9ta",
|
||||
"documentation": "https://www.home-assistant.io/integrations/lutron_caseta",
|
||||
"requirements": ["pylutron-caseta==0.11.0", "aiolip==1.1.6"],
|
||||
"requirements": ["pylutron-caseta==0.13.0"],
|
||||
"config_flow": true,
|
||||
"zeroconf": ["_leap._tcp.local."],
|
||||
"homekit": {
|
||||
|
|
|
@ -209,9 +209,6 @@ aiolifx==0.7.0
|
|||
# homeassistant.components.lifx
|
||||
aiolifx_effects==0.2.2
|
||||
|
||||
# homeassistant.components.lutron_caseta
|
||||
aiolip==1.1.6
|
||||
|
||||
# homeassistant.components.lookin
|
||||
aiolookin==0.1.0
|
||||
|
||||
|
@ -1625,7 +1622,7 @@ pylitejet==0.3.0
|
|||
pylitterbot==2021.12.0
|
||||
|
||||
# homeassistant.components.lutron_caseta
|
||||
pylutron-caseta==0.11.0
|
||||
pylutron-caseta==0.13.0
|
||||
|
||||
# homeassistant.components.lutron
|
||||
pylutron==0.2.8
|
||||
|
|
|
@ -142,9 +142,6 @@ aiohue==3.0.6
|
|||
# homeassistant.components.apache_kafka
|
||||
aiokafka==0.6.0
|
||||
|
||||
# homeassistant.components.lutron_caseta
|
||||
aiolip==1.1.6
|
||||
|
||||
# homeassistant.components.lookin
|
||||
aiolookin==0.1.0
|
||||
|
||||
|
@ -995,7 +992,7 @@ pylitejet==0.3.0
|
|||
pylitterbot==2021.12.0
|
||||
|
||||
# homeassistant.components.lutron_caseta
|
||||
pylutron-caseta==0.11.0
|
||||
pylutron-caseta==0.13.0
|
||||
|
||||
# homeassistant.components.mailgun
|
||||
pymailgunner==1.4
|
||||
|
|
Loading…
Reference in New Issue