mirror of
https://github.com/home-assistant/core.git
synced 2025-07-23 05:07:41 +00:00
Add support for area field from pylutron_caseta (#80221)
This commit is contained in:
parent
4cf0f9b197
commit
01c66aa7c1
@ -177,7 +177,7 @@ async def async_setup_entry(
|
|||||||
)
|
)
|
||||||
|
|
||||||
buttons = bridge.buttons
|
buttons = bridge.buttons
|
||||||
_async_register_bridge_device(hass, entry_id, bridge_device)
|
_async_register_bridge_device(hass, entry_id, bridge_device, bridge)
|
||||||
button_devices, device_info_by_device_id = _async_register_button_devices(
|
button_devices, device_info_by_device_id = _async_register_button_devices(
|
||||||
hass, entry_id, bridge, bridge_device, buttons
|
hass, entry_id, bridge, bridge_device, buttons
|
||||||
)
|
)
|
||||||
@ -196,18 +196,25 @@ async def async_setup_entry(
|
|||||||
|
|
||||||
@callback
|
@callback
|
||||||
def _async_register_bridge_device(
|
def _async_register_bridge_device(
|
||||||
hass: HomeAssistant, config_entry_id: str, bridge_device: dict
|
hass: HomeAssistant, config_entry_id: str, bridge_device: dict, bridge: Smartbridge
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Register the bridge device in the device registry."""
|
"""Register the bridge device in the device registry."""
|
||||||
device_registry = dr.async_get(hass)
|
device_registry = dr.async_get(hass)
|
||||||
device_registry.async_get_or_create(
|
|
||||||
name=bridge_device["name"],
|
device_args: DeviceInfo = {
|
||||||
manufacturer=MANUFACTURER,
|
"name": bridge_device["name"],
|
||||||
config_entry_id=config_entry_id,
|
"manufacturer": MANUFACTURER,
|
||||||
identifiers={(DOMAIN, bridge_device["serial"])},
|
"identifiers": {(DOMAIN, bridge_device["serial"])},
|
||||||
model=f"{bridge_device['model']} ({bridge_device['type']})",
|
"model": f"{bridge_device['model']} ({bridge_device['type']})",
|
||||||
configuration_url="https://device-login.lutron.com",
|
"via_device": (DOMAIN, bridge_device["serial"]),
|
||||||
)
|
"configuration_url": "https://device-login.lutron.com",
|
||||||
|
}
|
||||||
|
|
||||||
|
area = _area_name_from_id(bridge.areas, bridge_device["area"])
|
||||||
|
if area != UNASSIGNED_AREA:
|
||||||
|
device_args["suggested_area"] = area
|
||||||
|
|
||||||
|
device_registry.async_get_or_create(**device_args, config_entry_id=config_entry_id)
|
||||||
|
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
@ -241,7 +248,10 @@ def _async_register_button_devices(
|
|||||||
continue
|
continue
|
||||||
seen.add(ha_device_serial)
|
seen.add(ha_device_serial)
|
||||||
|
|
||||||
area, name = _area_and_name_from_name(ha_device["name"])
|
area = _area_name_from_id(bridge.areas, ha_device["area"])
|
||||||
|
# name field is still a combination of area and name from pylytron-caseta
|
||||||
|
# extract the name portion only.
|
||||||
|
name = ha_device["name"].split("_")[-1]
|
||||||
device_args: DeviceInfo = {
|
device_args: DeviceInfo = {
|
||||||
"name": f"{area} {name}",
|
"name": f"{area} {name}",
|
||||||
"manufacturer": MANUFACTURER,
|
"manufacturer": MANUFACTURER,
|
||||||
@ -265,12 +275,19 @@ def _handle_none_keypad_serial(keypad_device: dict, bridge_serial: int) -> str:
|
|||||||
return keypad_device["serial"] or f"{bridge_serial}_{keypad_device['device_id']}"
|
return keypad_device["serial"] or f"{bridge_serial}_{keypad_device['device_id']}"
|
||||||
|
|
||||||
|
|
||||||
def _area_and_name_from_name(device_name: str) -> tuple[str, str]:
|
def _area_name_from_id(areas: dict[str, dict], area_id: str) -> str:
|
||||||
"""Return the area and name from the devices internal name."""
|
"""Return the full area name including parent(s)."""
|
||||||
if "_" in device_name:
|
|
||||||
area_device_name = device_name.split("_", 1)
|
if area_id is None:
|
||||||
return area_device_name[0], area_device_name[1]
|
return UNASSIGNED_AREA
|
||||||
return UNASSIGNED_AREA, device_name
|
|
||||||
|
area = areas[area_id]
|
||||||
|
if "parent_id" in area:
|
||||||
|
parent_area = area["parent_id"]
|
||||||
|
if parent_area is not None:
|
||||||
|
return f"{_area_name_from_id(areas, parent_area)} {area['name']}"
|
||||||
|
|
||||||
|
return area["name"]
|
||||||
|
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
@ -316,7 +333,8 @@ def _async_subscribe_pico_remote_events(
|
|||||||
)
|
)
|
||||||
|
|
||||||
type_ = _lutron_model_to_device_type(ha_device["model"], ha_device["type"])
|
type_ = _lutron_model_to_device_type(ha_device["model"], ha_device["type"])
|
||||||
area, name = _area_and_name_from_name(ha_device["name"])
|
area = _area_name_from_id(bridge_device.areas, ha_device["area"])
|
||||||
|
name = ha_device["name"].split("_")[-1]
|
||||||
leap_button_number = device["button_number"]
|
leap_button_number = device["button_number"]
|
||||||
lip_button_number = async_get_lip_button(type_, leap_button_number)
|
lip_button_number = async_get_lip_button(type_, leap_button_number)
|
||||||
hass_device = dev_reg.async_get_device({(DOMAIN, ha_device_serial)})
|
hass_device = dev_reg.async_get_device({(DOMAIN, ha_device_serial)})
|
||||||
@ -377,8 +395,8 @@ class LutronCasetaDevice(Entity):
|
|||||||
if "parent_device" in device:
|
if "parent_device" in device:
|
||||||
# This is a child entity, handle the naming in button.py and switch.py
|
# This is a child entity, handle the naming in button.py and switch.py
|
||||||
return
|
return
|
||||||
|
area = _area_name_from_id(self._smartbridge.areas, device["area"])
|
||||||
area, name = _area_and_name_from_name(device["name"])
|
name = device["name"].split("_")[-1]
|
||||||
self._attr_name = full_name = f"{area} {name}"
|
self._attr_name = full_name = f"{area} {name}"
|
||||||
info = DeviceInfo(
|
info = DeviceInfo(
|
||||||
# Historically we used the device serial number for the identifier
|
# Historically we used the device serial number for the identifier
|
||||||
|
@ -6,13 +6,14 @@ from homeassistant.components.binary_sensor import (
|
|||||||
BinarySensorEntity,
|
BinarySensorEntity,
|
||||||
)
|
)
|
||||||
from homeassistant.config_entries import ConfigEntry
|
from homeassistant.config_entries import ConfigEntry
|
||||||
|
from homeassistant.const import ATTR_SUGGESTED_AREA
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.helpers.device_registry import DeviceEntryType
|
from homeassistant.helpers.device_registry import DeviceEntryType
|
||||||
from homeassistant.helpers.entity import DeviceInfo
|
from homeassistant.helpers.entity import DeviceInfo
|
||||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
|
|
||||||
from . import DOMAIN as CASETA_DOMAIN, LutronCasetaDevice, _area_and_name_from_name
|
from . import DOMAIN as CASETA_DOMAIN, LutronCasetaDevice, _area_name_from_id
|
||||||
from .const import CONFIG_URL, MANUFACTURER
|
from .const import CONFIG_URL, MANUFACTURER, UNASSIGNED_AREA
|
||||||
from .models import LutronCasetaData
|
from .models import LutronCasetaData
|
||||||
|
|
||||||
|
|
||||||
@ -43,7 +44,8 @@ class LutronOccupancySensor(LutronCasetaDevice, BinarySensorEntity):
|
|||||||
def __init__(self, device, data):
|
def __init__(self, device, data):
|
||||||
"""Init an occupancy sensor."""
|
"""Init an occupancy sensor."""
|
||||||
super().__init__(device, data)
|
super().__init__(device, data)
|
||||||
_, name = _area_and_name_from_name(device["name"])
|
area = _area_name_from_id(self._smartbridge.areas, device["area"])
|
||||||
|
name = f"{area} {device['device_name']}"
|
||||||
self._attr_name = name
|
self._attr_name = name
|
||||||
self._attr_device_info = DeviceInfo(
|
self._attr_device_info = DeviceInfo(
|
||||||
identifiers={(CASETA_DOMAIN, self.unique_id)},
|
identifiers={(CASETA_DOMAIN, self.unique_id)},
|
||||||
@ -54,6 +56,8 @@ class LutronOccupancySensor(LutronCasetaDevice, BinarySensorEntity):
|
|||||||
configuration_url=CONFIG_URL,
|
configuration_url=CONFIG_URL,
|
||||||
entry_type=DeviceEntryType.SERVICE,
|
entry_type=DeviceEntryType.SERVICE,
|
||||||
)
|
)
|
||||||
|
if area != UNASSIGNED_AREA:
|
||||||
|
self._attr_device_info[ATTR_SUGGESTED_AREA] = area
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_on(self):
|
def is_on(self):
|
||||||
|
@ -9,7 +9,6 @@ from homeassistant.core import HomeAssistant
|
|||||||
from homeassistant.helpers.entity import DeviceInfo
|
from homeassistant.helpers.entity import DeviceInfo
|
||||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
|
|
||||||
from . import _area_and_name_from_name
|
|
||||||
from .const import DOMAIN as CASETA_DOMAIN
|
from .const import DOMAIN as CASETA_DOMAIN
|
||||||
from .models import LutronCasetaData
|
from .models import LutronCasetaData
|
||||||
from .util import serial_to_unique_id
|
from .util import serial_to_unique_id
|
||||||
@ -42,7 +41,7 @@ class LutronCasetaScene(Scene):
|
|||||||
self._attr_device_info = DeviceInfo(
|
self._attr_device_info = DeviceInfo(
|
||||||
identifiers={(CASETA_DOMAIN, data.bridge_device["serial"])},
|
identifiers={(CASETA_DOMAIN, data.bridge_device["serial"])},
|
||||||
)
|
)
|
||||||
self._attr_name = _area_and_name_from_name(scene["name"])[1]
|
self._attr_name = scene["name"]
|
||||||
self._attr_unique_id = f"scene_{bridge_unique_id}_{self._scene_id}"
|
self._attr_unique_id = f"scene_{bridge_unique_id}_{self._scene_id}"
|
||||||
|
|
||||||
async def async_activate(self, **kwargs: Any) -> None:
|
async def async_activate(self, **kwargs: Any) -> None:
|
||||||
|
@ -105,7 +105,7 @@ class MockBridge:
|
|||||||
"""Initialize MockBridge instance with configured mock connectivity."""
|
"""Initialize MockBridge instance with configured mock connectivity."""
|
||||||
self.can_connect = can_connect
|
self.can_connect = can_connect
|
||||||
self.is_currently_connected = False
|
self.is_currently_connected = False
|
||||||
self.areas = {}
|
self.areas = self.load_areas()
|
||||||
self.occupancy_groups = {}
|
self.occupancy_groups = {}
|
||||||
self.scenes = self.get_scenes()
|
self.scenes = self.get_scenes()
|
||||||
self.devices = self.load_devices()
|
self.devices = self.load_devices()
|
||||||
@ -126,10 +126,28 @@ class MockBridge:
|
|||||||
"""Return whether the mock bridge is connected."""
|
"""Return whether the mock bridge is connected."""
|
||||||
return self.is_currently_connected
|
return self.is_currently_connected
|
||||||
|
|
||||||
|
def load_areas(self):
|
||||||
|
"""Loak mock areas into self.areas."""
|
||||||
|
return {
|
||||||
|
"898": {"id": "898", "name": "Basement", "parent_id": None},
|
||||||
|
"822": {"id": "822", "name": "Bedroom", "parent_id": "898"},
|
||||||
|
"910": {"id": "910", "name": "Bathroom", "parent_id": "898"},
|
||||||
|
"1024": {"id": "1024", "name": "Master Bedroom", "parent_id": None},
|
||||||
|
"1025": {"id": "1025", "name": "Kitchen", "parent_id": None},
|
||||||
|
"1026": {"id": "1026", "name": "Dining Room", "parent_id": None},
|
||||||
|
"1205": {"id": "1205", "name": "Hallway", "parent_id": None},
|
||||||
|
}
|
||||||
|
|
||||||
def load_devices(self):
|
def load_devices(self):
|
||||||
"""Load mock devices into self.devices."""
|
"""Load mock devices into self.devices."""
|
||||||
return {
|
return {
|
||||||
"1": {"serial": 1234, "name": "bridge", "model": "model", "type": "type"},
|
"1": {
|
||||||
|
"serial": 1234,
|
||||||
|
"name": "bridge",
|
||||||
|
"model": "model",
|
||||||
|
"type": "type",
|
||||||
|
"area": "1205",
|
||||||
|
},
|
||||||
"801": {
|
"801": {
|
||||||
"device_id": "801",
|
"device_id": "801",
|
||||||
"current_state": 100,
|
"current_state": 100,
|
||||||
@ -141,6 +159,7 @@ class MockBridge:
|
|||||||
"model": None,
|
"model": None,
|
||||||
"serial": None,
|
"serial": None,
|
||||||
"tilt": None,
|
"tilt": None,
|
||||||
|
"area": "822",
|
||||||
},
|
},
|
||||||
"802": {
|
"802": {
|
||||||
"device_id": "802",
|
"device_id": "802",
|
||||||
@ -153,6 +172,7 @@ class MockBridge:
|
|||||||
"model": None,
|
"model": None,
|
||||||
"serial": None,
|
"serial": None,
|
||||||
"tilt": None,
|
"tilt": None,
|
||||||
|
"area": "822",
|
||||||
},
|
},
|
||||||
"803": {
|
"803": {
|
||||||
"device_id": "803",
|
"device_id": "803",
|
||||||
@ -165,6 +185,7 @@ class MockBridge:
|
|||||||
"model": None,
|
"model": None,
|
||||||
"serial": None,
|
"serial": None,
|
||||||
"tilt": None,
|
"tilt": None,
|
||||||
|
"area": "910",
|
||||||
},
|
},
|
||||||
"804": {
|
"804": {
|
||||||
"device_id": "804",
|
"device_id": "804",
|
||||||
@ -177,6 +198,7 @@ class MockBridge:
|
|||||||
"model": None,
|
"model": None,
|
||||||
"serial": None,
|
"serial": None,
|
||||||
"tilt": None,
|
"tilt": None,
|
||||||
|
"area": "1024",
|
||||||
},
|
},
|
||||||
"901": {
|
"901": {
|
||||||
"device_id": "901",
|
"device_id": "901",
|
||||||
@ -189,6 +211,7 @@ class MockBridge:
|
|||||||
"model": None,
|
"model": None,
|
||||||
"serial": 5442321,
|
"serial": 5442321,
|
||||||
"tilt": None,
|
"tilt": None,
|
||||||
|
"area": "1025",
|
||||||
},
|
},
|
||||||
"9": {
|
"9": {
|
||||||
"device_id": "9",
|
"device_id": "9",
|
||||||
@ -203,7 +226,7 @@ class MockBridge:
|
|||||||
"model": "PJ2-3BRL-GXX-X01",
|
"model": "PJ2-3BRL-GXX-X01",
|
||||||
"serial": 68551522,
|
"serial": 68551522,
|
||||||
"device_name": "Pico",
|
"device_name": "Pico",
|
||||||
"area": "6",
|
"area": "1026",
|
||||||
},
|
},
|
||||||
"1355": {
|
"1355": {
|
||||||
"device_id": "1355",
|
"device_id": "1355",
|
||||||
|
@ -40,7 +40,15 @@ async def test_diagnostics(hass, hass_client) -> None:
|
|||||||
diag = await get_diagnostics_for_config_entry(hass, hass_client, config_entry)
|
diag = await get_diagnostics_for_config_entry(hass, hass_client, config_entry)
|
||||||
assert diag == {
|
assert diag == {
|
||||||
"data": {
|
"data": {
|
||||||
"areas": {},
|
"areas": {
|
||||||
|
"898": {"id": "898", "name": "Basement", "parent_id": None},
|
||||||
|
"822": {"id": "822", "name": "Bedroom", "parent_id": "898"},
|
||||||
|
"910": {"id": "910", "name": "Bathroom", "parent_id": "898"},
|
||||||
|
"1024": {"id": "1024", "name": "Master Bedroom", "parent_id": None},
|
||||||
|
"1025": {"id": "1025", "name": "Kitchen", "parent_id": None},
|
||||||
|
"1026": {"id": "1026", "name": "Dining Room", "parent_id": None},
|
||||||
|
"1205": {"id": "1205", "name": "Hallway", "parent_id": None},
|
||||||
|
},
|
||||||
"buttons": {
|
"buttons": {
|
||||||
"111": {
|
"111": {
|
||||||
"device_id": "111",
|
"device_id": "111",
|
||||||
@ -73,6 +81,7 @@ async def test_diagnostics(hass, hass_client) -> None:
|
|||||||
"name": "bridge",
|
"name": "bridge",
|
||||||
"serial": 1234,
|
"serial": 1234,
|
||||||
"type": "type",
|
"type": "type",
|
||||||
|
"area": "1205",
|
||||||
},
|
},
|
||||||
"801": {
|
"801": {
|
||||||
"device_id": "801",
|
"device_id": "801",
|
||||||
@ -85,6 +94,7 @@ async def test_diagnostics(hass, hass_client) -> None:
|
|||||||
"model": None,
|
"model": None,
|
||||||
"serial": None,
|
"serial": None,
|
||||||
"tilt": None,
|
"tilt": None,
|
||||||
|
"area": "822",
|
||||||
},
|
},
|
||||||
"802": {
|
"802": {
|
||||||
"device_id": "802",
|
"device_id": "802",
|
||||||
@ -97,6 +107,7 @@ async def test_diagnostics(hass, hass_client) -> None:
|
|||||||
"model": None,
|
"model": None,
|
||||||
"serial": None,
|
"serial": None,
|
||||||
"tilt": None,
|
"tilt": None,
|
||||||
|
"area": "822",
|
||||||
},
|
},
|
||||||
"803": {
|
"803": {
|
||||||
"device_id": "803",
|
"device_id": "803",
|
||||||
@ -109,6 +120,7 @@ async def test_diagnostics(hass, hass_client) -> None:
|
|||||||
"model": None,
|
"model": None,
|
||||||
"serial": None,
|
"serial": None,
|
||||||
"tilt": None,
|
"tilt": None,
|
||||||
|
"area": "910",
|
||||||
},
|
},
|
||||||
"804": {
|
"804": {
|
||||||
"device_id": "804",
|
"device_id": "804",
|
||||||
@ -121,6 +133,7 @@ async def test_diagnostics(hass, hass_client) -> None:
|
|||||||
"model": None,
|
"model": None,
|
||||||
"serial": None,
|
"serial": None,
|
||||||
"tilt": None,
|
"tilt": None,
|
||||||
|
"area": "1024",
|
||||||
},
|
},
|
||||||
"901": {
|
"901": {
|
||||||
"device_id": "901",
|
"device_id": "901",
|
||||||
@ -133,6 +146,7 @@ async def test_diagnostics(hass, hass_client) -> None:
|
|||||||
"model": None,
|
"model": None,
|
||||||
"serial": 5442321,
|
"serial": 5442321,
|
||||||
"tilt": None,
|
"tilt": None,
|
||||||
|
"area": "1025",
|
||||||
},
|
},
|
||||||
"9": {
|
"9": {
|
||||||
"device_id": "9",
|
"device_id": "9",
|
||||||
@ -147,7 +161,7 @@ async def test_diagnostics(hass, hass_client) -> None:
|
|||||||
"model": "PJ2-3BRL-GXX-X01",
|
"model": "PJ2-3BRL-GXX-X01",
|
||||||
"serial": 68551522,
|
"serial": 68551522,
|
||||||
"device_name": "Pico",
|
"device_name": "Pico",
|
||||||
"area": "6",
|
"area": "1026",
|
||||||
},
|
},
|
||||||
"1355": {
|
"1355": {
|
||||||
"device_id": "1355",
|
"device_id": "1355",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user