mirror of
https://github.com/home-assistant/core.git
synced 2025-07-21 20:27:08 +00:00
Add button entities for Lutron Caseta/RA3/HWQSX (#79963)
Co-authored-by: J. Nick Koston <nick@koston.org>
This commit is contained in:
parent
a396e35c21
commit
82322e3804
@ -79,6 +79,7 @@ PLATFORMS = [
|
|||||||
Platform.LIGHT,
|
Platform.LIGHT,
|
||||||
Platform.SCENE,
|
Platform.SCENE,
|
||||||
Platform.SWITCH,
|
Platform.SWITCH,
|
||||||
|
Platform.BUTTON,
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
@ -213,14 +214,14 @@ def _async_register_bridge_device(
|
|||||||
def _async_register_button_devices(
|
def _async_register_button_devices(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
config_entry_id: str,
|
config_entry_id: str,
|
||||||
bridge,
|
bridge: Smartbridge,
|
||||||
bridge_device,
|
bridge_device: dict[str, Any],
|
||||||
button_devices_by_id: dict[int, dict],
|
button_devices_by_id: dict[int, dict],
|
||||||
) -> tuple[dict[str, dict], dict[int, dict[str, Any]]]:
|
) -> tuple[dict[str, dict], dict[int, DeviceInfo]]:
|
||||||
"""Register button devices (Pico Remotes) in the device registry."""
|
"""Register button devices (Pico Remotes) in the device registry."""
|
||||||
device_registry = dr.async_get(hass)
|
device_registry = dr.async_get(hass)
|
||||||
button_devices_by_dr_id: dict[str, dict] = {}
|
button_devices_by_dr_id: dict[str, dict] = {}
|
||||||
device_info_by_device_id: dict[int, dict[str, Any]] = {}
|
device_info_by_device_id: dict[int, DeviceInfo] = {}
|
||||||
seen: set[str] = set()
|
seen: set[str] = set()
|
||||||
bridge_devices = bridge.get_devices()
|
bridge_devices = bridge.get_devices()
|
||||||
|
|
||||||
@ -241,10 +242,9 @@ def _async_register_button_devices(
|
|||||||
seen.add(ha_device_serial)
|
seen.add(ha_device_serial)
|
||||||
|
|
||||||
area, name = _area_and_name_from_name(ha_device["name"])
|
area, name = _area_and_name_from_name(ha_device["name"])
|
||||||
device_args: dict[str, Any] = {
|
device_args: DeviceInfo = {
|
||||||
"name": f"{area} {name}",
|
"name": f"{area} {name}",
|
||||||
"manufacturer": MANUFACTURER,
|
"manufacturer": MANUFACTURER,
|
||||||
"config_entry_id": config_entry_id,
|
|
||||||
"identifiers": {(DOMAIN, ha_device_serial)},
|
"identifiers": {(DOMAIN, ha_device_serial)},
|
||||||
"model": f"{ha_device['model']} ({ha_device['type']})",
|
"model": f"{ha_device['model']} ({ha_device['type']})",
|
||||||
"via_device": (DOMAIN, bridge_device["serial"]),
|
"via_device": (DOMAIN, bridge_device["serial"]),
|
||||||
@ -252,7 +252,9 @@ def _async_register_button_devices(
|
|||||||
if area != UNASSIGNED_AREA:
|
if area != UNASSIGNED_AREA:
|
||||||
device_args["suggested_area"] = area
|
device_args["suggested_area"] = area
|
||||||
|
|
||||||
dr_device = device_registry.async_get_or_create(**device_args)
|
dr_device = device_registry.async_get_or_create(
|
||||||
|
**device_args, config_entry_id=config_entry_id
|
||||||
|
)
|
||||||
button_devices_by_dr_id[dr_device.id] = ha_device
|
button_devices_by_dr_id[dr_device.id] = ha_device
|
||||||
device_info_by_device_id.setdefault(ha_device["device_id"], device_args)
|
device_info_by_device_id.setdefault(ha_device["device_id"], device_args)
|
||||||
|
|
||||||
@ -358,7 +360,7 @@ class LutronCasetaDevice(Entity):
|
|||||||
|
|
||||||
_attr_should_poll = False
|
_attr_should_poll = False
|
||||||
|
|
||||||
def __init__(self, device, data):
|
def __init__(self, device: dict[str, Any], data: LutronCasetaData) -> None:
|
||||||
"""Set up the base class.
|
"""Set up the base class.
|
||||||
|
|
||||||
[:param]device the device metadata
|
[:param]device the device metadata
|
||||||
@ -372,22 +374,19 @@ class LutronCasetaDevice(Entity):
|
|||||||
if "serial" not in self._device:
|
if "serial" not in self._device:
|
||||||
return
|
return
|
||||||
|
|
||||||
if "parent_device" in device and (
|
if "parent_device" in device:
|
||||||
parent_device_info := data.device_info_by_device_id.get(
|
# This is a child entity, handle the naming in button.py and switch.py
|
||||||
device["parent_device"]
|
|
||||||
)
|
|
||||||
):
|
|
||||||
# Append the child device name to the end of the parent keypad name to create the entity name
|
|
||||||
self._attr_name = f'{parent_device_info["name"]} {device["device_name"]}'
|
|
||||||
# Set the device_info to the same as the Parent Keypad
|
|
||||||
# The entities will be nested inside the keypad device
|
|
||||||
self._attr_device_info = parent_device_info
|
|
||||||
return
|
return
|
||||||
|
|
||||||
area, name = _area_and_name_from_name(device["name"])
|
area, name = _area_and_name_from_name(device["name"])
|
||||||
self._attr_name = full_name = f"{area} {name}"
|
self._attr_name = full_name = f"{area} {name}"
|
||||||
info = DeviceInfo(
|
info = DeviceInfo(
|
||||||
identifiers={(DOMAIN, self._handle_none_serial(self.serial))},
|
# Historically we used the device serial number for the identifier
|
||||||
|
# but the serial is usually an integer and a string is expected
|
||||||
|
# here. Since it would be a breaking change to change the identifier
|
||||||
|
# we are ignoring the type error here until it can be migrated to
|
||||||
|
# a string in a future release.
|
||||||
|
identifiers={(DOMAIN, self._handle_none_serial(self.serial))}, # type: ignore[arg-type]
|
||||||
manufacturer=MANUFACTURER,
|
manufacturer=MANUFACTURER,
|
||||||
model=f"{device['model']} ({device['type']})",
|
model=f"{device['model']} ({device['type']})",
|
||||||
name=full_name,
|
name=full_name,
|
||||||
@ -402,7 +401,7 @@ class LutronCasetaDevice(Entity):
|
|||||||
"""Register callbacks."""
|
"""Register callbacks."""
|
||||||
self._smartbridge.add_subscriber(self.device_id, self.async_write_ha_state)
|
self._smartbridge.add_subscriber(self.device_id, self.async_write_ha_state)
|
||||||
|
|
||||||
def _handle_none_serial(self, serial: str | None) -> str | int:
|
def _handle_none_serial(self, serial: str | int | None) -> str | int:
|
||||||
"""Handle None serial returned by RA3 and QSX processors."""
|
"""Handle None serial returned by RA3 and QSX processors."""
|
||||||
if serial is None:
|
if serial is None:
|
||||||
return f"{self._bridge_unique_id}_{self.device_id}"
|
return f"{self._bridge_unique_id}_{self.device_id}"
|
||||||
@ -414,7 +413,7 @@ class LutronCasetaDevice(Entity):
|
|||||||
return self._device["device_id"]
|
return self._device["device_id"]
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def serial(self):
|
def serial(self) -> int | None:
|
||||||
"""Return the serial number of the device."""
|
"""Return the serial number of the device."""
|
||||||
return self._device["serial"]
|
return self._device["serial"]
|
||||||
|
|
||||||
@ -426,7 +425,12 @@ class LutronCasetaDevice(Entity):
|
|||||||
@property
|
@property
|
||||||
def extra_state_attributes(self):
|
def extra_state_attributes(self):
|
||||||
"""Return the state attributes."""
|
"""Return the state attributes."""
|
||||||
return {"device_id": self.device_id, "zone_id": self._device["zone"]}
|
attributes = {
|
||||||
|
"device_id": self.device_id,
|
||||||
|
}
|
||||||
|
if zone := self._device.get("zone"):
|
||||||
|
attributes["zone_id"] = zone
|
||||||
|
return attributes
|
||||||
|
|
||||||
|
|
||||||
class LutronCasetaDeviceUpdatableEntity(LutronCasetaDevice):
|
class LutronCasetaDeviceUpdatableEntity(LutronCasetaDevice):
|
||||||
|
98
homeassistant/components/lutron_caseta/button.py
Normal file
98
homeassistant/components/lutron_caseta/button.py
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
"""Support for pico and keypad buttons."""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
from homeassistant.components.button import ButtonEntity
|
||||||
|
from homeassistant.config_entries import ConfigEntry
|
||||||
|
from homeassistant.core import HomeAssistant
|
||||||
|
from homeassistant.helpers.entity import DeviceInfo
|
||||||
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
|
|
||||||
|
from . import LutronCasetaDevice
|
||||||
|
from .const import DOMAIN as CASETA_DOMAIN
|
||||||
|
from .device_trigger import (
|
||||||
|
LEAP_TO_DEVICE_TYPE_SUBTYPE_MAP,
|
||||||
|
_lutron_model_to_device_type,
|
||||||
|
)
|
||||||
|
from .models import LutronCasetaData
|
||||||
|
|
||||||
|
|
||||||
|
async def async_setup_entry(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
config_entry: ConfigEntry,
|
||||||
|
async_add_entities: AddEntitiesCallback,
|
||||||
|
) -> None:
|
||||||
|
"""Set up Lutron pico and keypad buttons."""
|
||||||
|
data: LutronCasetaData = hass.data[CASETA_DOMAIN][config_entry.entry_id]
|
||||||
|
bridge = data.bridge
|
||||||
|
button_devices = bridge.get_buttons()
|
||||||
|
all_devices = data.bridge.get_devices()
|
||||||
|
device_info_by_device_id = data.device_info_by_device_id
|
||||||
|
entities: list[LutronCasetaButton] = []
|
||||||
|
|
||||||
|
for device in button_devices.values():
|
||||||
|
|
||||||
|
parent_device_info = device_info_by_device_id[device["parent_device"]]
|
||||||
|
|
||||||
|
enabled_default = True
|
||||||
|
if not (device_name := device.get("device_name")):
|
||||||
|
# device name (button name) is missing, probably a caseta pico
|
||||||
|
# try to get the name using the button number from the triggers
|
||||||
|
# disable the button by default
|
||||||
|
enabled_default = False
|
||||||
|
keypad_device = all_devices[device["parent_device"]]
|
||||||
|
button_numbers = LEAP_TO_DEVICE_TYPE_SUBTYPE_MAP.get(
|
||||||
|
_lutron_model_to_device_type(
|
||||||
|
keypad_device["model"], keypad_device["type"]
|
||||||
|
),
|
||||||
|
{},
|
||||||
|
)
|
||||||
|
device_name = (
|
||||||
|
button_numbers.get(
|
||||||
|
int(device["button_number"]),
|
||||||
|
f"button {device['button_number']}",
|
||||||
|
)
|
||||||
|
.replace("_", " ")
|
||||||
|
.title()
|
||||||
|
)
|
||||||
|
|
||||||
|
# Append the child device name to the end of the parent keypad name to create the entity name
|
||||||
|
full_name = f'{parent_device_info.get("name")} {device_name}'
|
||||||
|
# Set the device_info to the same as the Parent Keypad
|
||||||
|
# The entities will be nested inside the keypad device
|
||||||
|
entities.append(
|
||||||
|
LutronCasetaButton(
|
||||||
|
device, data, full_name, enabled_default, parent_device_info
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
if entities:
|
||||||
|
async_add_entities(entities)
|
||||||
|
|
||||||
|
|
||||||
|
class LutronCasetaButton(LutronCasetaDevice, ButtonEntity):
|
||||||
|
"""Representation of a Lutron pico and keypad button."""
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
device: dict[str, Any],
|
||||||
|
data: LutronCasetaData,
|
||||||
|
full_name: str,
|
||||||
|
enabled_default: bool,
|
||||||
|
device_info: DeviceInfo,
|
||||||
|
) -> None:
|
||||||
|
"""Init a button entity."""
|
||||||
|
super().__init__(device, data)
|
||||||
|
self._attr_entity_registry_enabled_default = enabled_default
|
||||||
|
self._attr_name = full_name
|
||||||
|
self._attr_device_info = device_info
|
||||||
|
|
||||||
|
async def async_press(self) -> None:
|
||||||
|
"""Send a button press event."""
|
||||||
|
await self._smartbridge.tap_button(self.device_id)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def serial(self):
|
||||||
|
"""Buttons shouldn't have serial numbers, Return None."""
|
||||||
|
return None
|
@ -6,6 +6,8 @@ from typing import Any
|
|||||||
|
|
||||||
from pylutron_caseta.smartbridge import Smartbridge
|
from pylutron_caseta.smartbridge import Smartbridge
|
||||||
|
|
||||||
|
from homeassistant.helpers.entity import DeviceInfo
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class LutronCasetaData:
|
class LutronCasetaData:
|
||||||
@ -14,4 +16,4 @@ class LutronCasetaData:
|
|||||||
bridge: Smartbridge
|
bridge: Smartbridge
|
||||||
bridge_device: dict[str, Any]
|
bridge_device: dict[str, Any]
|
||||||
button_devices: dict[str, dict]
|
button_devices: dict[str, dict]
|
||||||
device_info_by_device_id: dict[int, dict[str, Any]]
|
device_info_by_device_id: dict[int, DeviceInfo]
|
||||||
|
@ -33,6 +33,9 @@
|
|||||||
"button_2": "Second button",
|
"button_2": "Second button",
|
||||||
"button_3": "Third button",
|
"button_3": "Third button",
|
||||||
"button_4": "Fourth button",
|
"button_4": "Fourth button",
|
||||||
|
"button_5": "Fifth button",
|
||||||
|
"button_6": "Sixth button",
|
||||||
|
"button_7": "Seventh button",
|
||||||
"group_1_button_1": "First Group first button",
|
"group_1_button_1": "First Group first button",
|
||||||
"group_1_button_2": "First Group second button",
|
"group_1_button_2": "First Group second button",
|
||||||
"group_2_button_1": "Second Group first button",
|
"group_2_button_1": "Second Group first button",
|
||||||
|
@ -33,6 +33,22 @@ async def async_setup_entry(
|
|||||||
class LutronCasetaLight(LutronCasetaDeviceUpdatableEntity, SwitchEntity):
|
class LutronCasetaLight(LutronCasetaDeviceUpdatableEntity, SwitchEntity):
|
||||||
"""Representation of a Lutron Caseta switch."""
|
"""Representation of a Lutron Caseta switch."""
|
||||||
|
|
||||||
|
def __init__(self, device, data):
|
||||||
|
"""Init a button entity."""
|
||||||
|
|
||||||
|
super().__init__(device, data)
|
||||||
|
self._enabled_default = True
|
||||||
|
|
||||||
|
if "parent_device" not in device:
|
||||||
|
return
|
||||||
|
|
||||||
|
parent_device_info = data.device_info_by_device_id.get(device["parent_device"])
|
||||||
|
# Append the child device name to the end of the parent keypad name to create the entity name
|
||||||
|
self._attr_name = f'{parent_device_info["name"]} {device["device_name"]}'
|
||||||
|
# Set the device_info to the same as the Parent Keypad
|
||||||
|
# The entities will be nested inside the keypad device
|
||||||
|
self._attr_device_info = parent_device_info
|
||||||
|
|
||||||
async def async_turn_on(self, **kwargs: Any) -> None:
|
async def async_turn_on(self, **kwargs: Any) -> None:
|
||||||
"""Turn the switch on."""
|
"""Turn the switch on."""
|
||||||
await self._smartbridge.turn_on(self.device_id)
|
await self._smartbridge.turn_on(self.device_id)
|
||||||
|
@ -33,6 +33,9 @@
|
|||||||
"button_2": "Second button",
|
"button_2": "Second button",
|
||||||
"button_3": "Third button",
|
"button_3": "Third button",
|
||||||
"button_4": "Fourth button",
|
"button_4": "Fourth button",
|
||||||
|
"button_5": "Fifth button",
|
||||||
|
"button_6": "Sixth button",
|
||||||
|
"button_7": "Seventh button",
|
||||||
"close_1": "Close 1",
|
"close_1": "Close 1",
|
||||||
"close_2": "Close 2",
|
"close_2": "Close 2",
|
||||||
"close_3": "Close 3",
|
"close_3": "Close 3",
|
||||||
|
@ -105,11 +105,11 @@ 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.buttons = {}
|
|
||||||
self.areas = {}
|
self.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()
|
||||||
|
self.buttons = self.load_buttons()
|
||||||
|
|
||||||
async def connect(self):
|
async def connect(self):
|
||||||
"""Connect the mock bridge."""
|
"""Connect the mock bridge."""
|
||||||
@ -119,6 +119,9 @@ class MockBridge:
|
|||||||
def add_subscriber(self, device_id: str, callback_):
|
def add_subscriber(self, device_id: str, callback_):
|
||||||
"""Mock a listener to be notified of state changes."""
|
"""Mock a listener to be notified of state changes."""
|
||||||
|
|
||||||
|
def add_button_subscriber(self, button_id: str, callback_):
|
||||||
|
"""Mock a listener for button presses."""
|
||||||
|
|
||||||
def is_connected(self):
|
def is_connected(self):
|
||||||
"""Return whether the mock bridge is connected."""
|
"""Return whether the mock bridge is connected."""
|
||||||
return self.is_currently_connected
|
return self.is_currently_connected
|
||||||
@ -187,6 +190,64 @@ class MockBridge:
|
|||||||
"serial": 5442321,
|
"serial": 5442321,
|
||||||
"tilt": None,
|
"tilt": None,
|
||||||
},
|
},
|
||||||
|
"9": {
|
||||||
|
"device_id": "9",
|
||||||
|
"current_state": -1,
|
||||||
|
"fan_speed": None,
|
||||||
|
"tilt": None,
|
||||||
|
"zone": None,
|
||||||
|
"name": "Dining Room_Pico",
|
||||||
|
"button_groups": ["4"],
|
||||||
|
"occupancy_sensors": None,
|
||||||
|
"type": "Pico3ButtonRaiseLower",
|
||||||
|
"model": "PJ2-3BRL-GXX-X01",
|
||||||
|
"serial": 68551522,
|
||||||
|
"device_name": "Pico",
|
||||||
|
"area": "6",
|
||||||
|
},
|
||||||
|
"1355": {
|
||||||
|
"device_id": "1355",
|
||||||
|
"current_state": -1,
|
||||||
|
"fan_speed": None,
|
||||||
|
"zone": None,
|
||||||
|
"name": "Hallway_Main Stairs Position 1 Keypad",
|
||||||
|
"button_groups": ["1363"],
|
||||||
|
"type": "SunnataKeypad",
|
||||||
|
"model": "RRST-W3RL-XX",
|
||||||
|
"serial": 66286451,
|
||||||
|
"control_station_name": "Main Stairs",
|
||||||
|
"device_name": "Position 1",
|
||||||
|
"area": "1205",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
def load_buttons(self):
|
||||||
|
"""Load mock buttons into self.buttons."""
|
||||||
|
return {
|
||||||
|
"111": {
|
||||||
|
"device_id": "111",
|
||||||
|
"current_state": "Release",
|
||||||
|
"button_number": 0,
|
||||||
|
"name": "Dining Room_Pico",
|
||||||
|
"type": "Pico3ButtonRaiseLower",
|
||||||
|
"model": "PJ2-3BRL-GXX-X01",
|
||||||
|
"serial": 68551522,
|
||||||
|
"parent_device": "9",
|
||||||
|
},
|
||||||
|
"1372": {
|
||||||
|
"device_id": "1372",
|
||||||
|
"current_state": "Release",
|
||||||
|
"button_number": 3,
|
||||||
|
"button_group": "1363",
|
||||||
|
"name": "Hallway_Main Stairs Position 1 Keypad",
|
||||||
|
"type": "SunnataKeypad",
|
||||||
|
"model": "RRST-W3RL-XX",
|
||||||
|
"serial": 66286451,
|
||||||
|
"button_name": "Kitchen Pendants",
|
||||||
|
"button_led": "1362",
|
||||||
|
"device_name": "Kitchen Pendants",
|
||||||
|
"parent_device": "1355",
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
def get_devices(self) -> dict[str, dict]:
|
def get_devices(self) -> dict[str, dict]:
|
||||||
@ -228,6 +289,13 @@ class MockBridge:
|
|||||||
"""Return scenes on the bridge."""
|
"""Return scenes on the bridge."""
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
|
def get_buttons(self):
|
||||||
|
"""Will return all known buttons connected to the bridge/processor."""
|
||||||
|
return self.buttons
|
||||||
|
|
||||||
|
def tap_button(self, button_id: str):
|
||||||
|
"""Mock a button press and release message for the given button ID."""
|
||||||
|
|
||||||
async def close(self):
|
async def close(self):
|
||||||
"""Close the mock bridge connection."""
|
"""Close the mock bridge connection."""
|
||||||
self.is_currently_connected = False
|
self.is_currently_connected = False
|
||||||
|
50
tests/components/lutron_caseta/test_button.py
Normal file
50
tests/components/lutron_caseta/test_button.py
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
"""Tests for the Lutron Caseta integration."""
|
||||||
|
|
||||||
|
from homeassistant.components.button import DOMAIN as BUTTON_DOMAIN, SERVICE_PRESS
|
||||||
|
from homeassistant.const import ATTR_ENTITY_ID, STATE_UNKNOWN
|
||||||
|
from homeassistant.core import HomeAssistant
|
||||||
|
from homeassistant.helpers import entity_registry as er
|
||||||
|
|
||||||
|
from . import MockBridge, async_setup_integration
|
||||||
|
|
||||||
|
|
||||||
|
async def test_button_unique_id(hass: HomeAssistant) -> None:
|
||||||
|
"""Test a button unique id."""
|
||||||
|
await async_setup_integration(hass, MockBridge)
|
||||||
|
|
||||||
|
ra3_button_entity_id = (
|
||||||
|
"button.hallway_main_stairs_position_1_keypad_kitchen_pendants"
|
||||||
|
)
|
||||||
|
caseta_button_entity_id = "button.dining_room_pico_on"
|
||||||
|
|
||||||
|
entity_registry = er.async_get(hass)
|
||||||
|
|
||||||
|
# Assert that Caseta buttons will have the bridge serial hash and the zone id as the uniqueID
|
||||||
|
assert entity_registry.async_get(ra3_button_entity_id).unique_id == "000004d2_1372"
|
||||||
|
assert (
|
||||||
|
entity_registry.async_get(caseta_button_entity_id).unique_id == "000004d2_111"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def test_button_press(hass: HomeAssistant) -> None:
|
||||||
|
"""Test a button press."""
|
||||||
|
await async_setup_integration(hass, MockBridge)
|
||||||
|
|
||||||
|
ra3_button_entity_id = (
|
||||||
|
"button.hallway_main_stairs_position_1_keypad_kitchen_pendants"
|
||||||
|
)
|
||||||
|
|
||||||
|
state = hass.states.get(ra3_button_entity_id)
|
||||||
|
assert state
|
||||||
|
assert state.state == STATE_UNKNOWN
|
||||||
|
|
||||||
|
await hass.services.async_call(
|
||||||
|
BUTTON_DOMAIN,
|
||||||
|
SERVICE_PRESS,
|
||||||
|
{ATTR_ENTITY_ID: ra3_button_entity_id},
|
||||||
|
blocking=False,
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
state = hass.states.get(ra3_button_entity_id)
|
||||||
|
assert state
|
@ -41,7 +41,32 @@ async def test_diagnostics(hass, hass_client) -> None:
|
|||||||
assert diag == {
|
assert diag == {
|
||||||
"data": {
|
"data": {
|
||||||
"areas": {},
|
"areas": {},
|
||||||
"buttons": {},
|
"buttons": {
|
||||||
|
"111": {
|
||||||
|
"device_id": "111",
|
||||||
|
"current_state": "Release",
|
||||||
|
"button_number": 0,
|
||||||
|
"name": "Dining Room_Pico",
|
||||||
|
"type": "Pico3ButtonRaiseLower",
|
||||||
|
"model": "PJ2-3BRL-GXX-X01",
|
||||||
|
"serial": 68551522,
|
||||||
|
"parent_device": "9",
|
||||||
|
},
|
||||||
|
"1372": {
|
||||||
|
"device_id": "1372",
|
||||||
|
"current_state": "Release",
|
||||||
|
"button_number": 3,
|
||||||
|
"button_group": "1363",
|
||||||
|
"name": "Hallway_Main Stairs Position 1 Keypad",
|
||||||
|
"type": "SunnataKeypad",
|
||||||
|
"model": "RRST-W3RL-XX",
|
||||||
|
"serial": 66286451,
|
||||||
|
"button_name": "Kitchen Pendants",
|
||||||
|
"button_led": "1362",
|
||||||
|
"device_name": "Kitchen Pendants",
|
||||||
|
"parent_device": "1355",
|
||||||
|
},
|
||||||
|
},
|
||||||
"devices": {
|
"devices": {
|
||||||
"1": {
|
"1": {
|
||||||
"model": "model",
|
"model": "model",
|
||||||
@ -109,6 +134,35 @@ async def test_diagnostics(hass, hass_client) -> None:
|
|||||||
"serial": 5442321,
|
"serial": 5442321,
|
||||||
"tilt": None,
|
"tilt": None,
|
||||||
},
|
},
|
||||||
|
"9": {
|
||||||
|
"device_id": "9",
|
||||||
|
"current_state": -1,
|
||||||
|
"fan_speed": None,
|
||||||
|
"tilt": None,
|
||||||
|
"zone": None,
|
||||||
|
"name": "Dining Room_Pico",
|
||||||
|
"button_groups": ["4"],
|
||||||
|
"occupancy_sensors": None,
|
||||||
|
"type": "Pico3ButtonRaiseLower",
|
||||||
|
"model": "PJ2-3BRL-GXX-X01",
|
||||||
|
"serial": 68551522,
|
||||||
|
"device_name": "Pico",
|
||||||
|
"area": "6",
|
||||||
|
},
|
||||||
|
"1355": {
|
||||||
|
"device_id": "1355",
|
||||||
|
"current_state": -1,
|
||||||
|
"fan_speed": None,
|
||||||
|
"zone": None,
|
||||||
|
"name": "Hallway_Main Stairs Position 1 Keypad",
|
||||||
|
"button_groups": ["1363"],
|
||||||
|
"type": "SunnataKeypad",
|
||||||
|
"model": "RRST-W3RL-XX",
|
||||||
|
"serial": 66286451,
|
||||||
|
"control_station_name": "Main Stairs",
|
||||||
|
"device_name": "Position 1",
|
||||||
|
"area": "1205",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
"occupancy_groups": {},
|
"occupancy_groups": {},
|
||||||
"scenes": {},
|
"scenes": {},
|
||||||
|
Loading…
x
Reference in New Issue
Block a user