Reduce bond startup time (#73506)

This commit is contained in:
J. Nick Koston 2022-06-14 20:30:59 -10:00 committed by GitHub
parent c64b108789
commit 1e956bc52f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 54 additions and 46 deletions

View File

@ -287,10 +287,10 @@ class BondButtonEntity(BondEntity, ButtonEntity):
description: BondButtonEntityDescription, description: BondButtonEntityDescription,
) -> None: ) -> None:
"""Init Bond button.""" """Init Bond button."""
self.entity_description = description
super().__init__( super().__init__(
hub, device, bpup_subs, description.name, description.key.lower() hub, device, bpup_subs, description.name, description.key.lower()
) )
self.entity_description = description
async def async_press(self, **kwargs: Any) -> None: async def async_press(self, **kwargs: Any) -> None:
"""Press the button.""" """Press the button."""
@ -302,5 +302,5 @@ class BondButtonEntity(BondEntity, ButtonEntity):
action = Action(self.entity_description.key) action = Action(self.entity_description.key)
await self._hub.bond.action(self._device.device_id, action) await self._hub.bond.action(self._device.device_id, action)
def _apply_state(self, state: dict) -> None: def _apply_state(self) -> None:
"""Apply the state.""" """Apply the state."""

View File

@ -13,7 +13,6 @@ from homeassistant.components.cover import (
) )
from homeassistant.config_entries import ConfigEntry from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity import Entity
from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.entity_platform import AddEntitiesCallback
from .const import BPUP_SUBS, DOMAIN, HUB from .const import BPUP_SUBS, DOMAIN, HUB
@ -40,14 +39,11 @@ async def async_setup_entry(
data = hass.data[DOMAIN][entry.entry_id] data = hass.data[DOMAIN][entry.entry_id]
hub: BondHub = data[HUB] hub: BondHub = data[HUB]
bpup_subs: BPUPSubscriptions = data[BPUP_SUBS] bpup_subs: BPUPSubscriptions = data[BPUP_SUBS]
async_add_entities(
covers: list[Entity] = [
BondCover(hub, device, bpup_subs) BondCover(hub, device, bpup_subs)
for device in hub.devices for device in hub.devices
if device.type == DeviceType.MOTORIZED_SHADES if device.type == DeviceType.MOTORIZED_SHADES
] )
async_add_entities(covers, True)
class BondCover(BondEntity, CoverEntity): class BondCover(BondEntity, CoverEntity):
@ -78,7 +74,8 @@ class BondCover(BondEntity, CoverEntity):
supported_features |= CoverEntityFeature.STOP_TILT supported_features |= CoverEntityFeature.STOP_TILT
self._attr_supported_features = supported_features self._attr_supported_features = supported_features
def _apply_state(self, state: dict) -> None: def _apply_state(self) -> None:
state = self._device.state
cover_open = state.get("open") cover_open = state.get("open")
self._attr_is_closed = None if cover_open is None else cover_open == 0 self._attr_is_closed = None if cover_open is None else cover_open == 0
if (bond_position := state.get("position")) is not None: if (bond_position := state.get("position")) is not None:

View File

@ -64,6 +64,8 @@ class BondEntity(Entity):
self._attr_name = f"{device.name} {sub_device_name}" self._attr_name = f"{device.name} {sub_device_name}"
else: else:
self._attr_name = device.name self._attr_name = device.name
self._attr_assumed_state = self._hub.is_bridge and not self._device.trust_state
self._apply_state()
@property @property
def device_info(self) -> DeviceInfo: def device_info(self) -> DeviceInfo:
@ -137,10 +139,9 @@ class BondEntity(Entity):
self._attr_available = False self._attr_available = False
else: else:
self._async_state_callback(state) self._async_state_callback(state)
self._attr_assumed_state = self._hub.is_bridge and not self._device.trust_state
@abstractmethod @abstractmethod
def _apply_state(self, state: dict) -> None: def _apply_state(self) -> None:
raise NotImplementedError raise NotImplementedError
@callback @callback
@ -153,7 +154,8 @@ class BondEntity(Entity):
_LOGGER.debug( _LOGGER.debug(
"Device state for %s (%s) is:\n%s", self.name, self.entity_id, state "Device state for %s (%s) is:\n%s", self.name, self.entity_id, state
) )
self._apply_state(state) self._device.state = state
self._apply_state()
@callback @callback
def _async_bpup_callback(self, json_msg: dict) -> None: def _async_bpup_callback(self, json_msg: dict) -> None:

View File

@ -19,7 +19,6 @@ from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.exceptions import HomeAssistantError from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers import entity_platform from homeassistant.helpers import entity_platform
from homeassistant.helpers.entity import Entity
from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.util.percentage import ( from homeassistant.util.percentage import (
int_states_in_range, int_states_in_range,
@ -46,20 +45,17 @@ async def async_setup_entry(
hub: BondHub = data[HUB] hub: BondHub = data[HUB]
bpup_subs: BPUPSubscriptions = data[BPUP_SUBS] bpup_subs: BPUPSubscriptions = data[BPUP_SUBS]
platform = entity_platform.async_get_current_platform() platform = entity_platform.async_get_current_platform()
fans: list[Entity] = [
BondFan(hub, device, bpup_subs)
for device in hub.devices
if DeviceType.is_fan(device.type)
]
platform.async_register_entity_service( platform.async_register_entity_service(
SERVICE_SET_FAN_SPEED_TRACKED_STATE, SERVICE_SET_FAN_SPEED_TRACKED_STATE,
{vol.Required("speed"): vol.All(vol.Number(scale=0), vol.Range(0, 100))}, {vol.Required("speed"): vol.All(vol.Number(scale=0), vol.Range(0, 100))},
"async_set_speed_belief", "async_set_speed_belief",
) )
async_add_entities(fans, True) async_add_entities(
BondFan(hub, device, bpup_subs)
for device in hub.devices
if DeviceType.is_fan(device.type)
)
class BondFan(BondEntity, FanEntity): class BondFan(BondEntity, FanEntity):
@ -69,15 +65,15 @@ class BondFan(BondEntity, FanEntity):
self, hub: BondHub, device: BondDevice, bpup_subs: BPUPSubscriptions self, hub: BondHub, device: BondDevice, bpup_subs: BPUPSubscriptions
) -> None: ) -> None:
"""Create HA entity representing Bond fan.""" """Create HA entity representing Bond fan."""
super().__init__(hub, device, bpup_subs)
self._power: bool | None = None self._power: bool | None = None
self._speed: int | None = None self._speed: int | None = None
self._direction: int | None = None self._direction: int | None = None
super().__init__(hub, device, bpup_subs)
if self._device.has_action(Action.BREEZE_ON): if self._device.has_action(Action.BREEZE_ON):
self._attr_preset_modes = [PRESET_MODE_BREEZE] self._attr_preset_modes = [PRESET_MODE_BREEZE]
def _apply_state(self, state: dict) -> None: def _apply_state(self) -> None:
state = self._device.state
self._power = state.get("power") self._power = state.get("power")
self._speed = state.get("speed") self._speed = state.get("speed")
self._direction = state.get("direction") self._direction = state.get("direction")

View File

@ -115,7 +115,6 @@ async def async_setup_entry(
async_add_entities( async_add_entities(
fan_lights + fan_up_lights + fan_down_lights + fireplaces + fp_lights + lights, fan_lights + fan_up_lights + fan_down_lights + fireplaces + fp_lights + lights,
True,
) )
@ -170,7 +169,8 @@ class BondLight(BondBaseLight, BondEntity, LightEntity):
self._attr_color_mode = ColorMode.BRIGHTNESS self._attr_color_mode = ColorMode.BRIGHTNESS
self._attr_supported_color_modes = {ColorMode.BRIGHTNESS} self._attr_supported_color_modes = {ColorMode.BRIGHTNESS}
def _apply_state(self, state: dict) -> None: def _apply_state(self) -> None:
state = self._device.state
self._attr_is_on = state.get("light") == 1 self._attr_is_on = state.get("light") == 1
brightness = state.get("brightness") brightness = state.get("brightness")
self._attr_brightness = round(brightness * 255 / 100) if brightness else None self._attr_brightness = round(brightness * 255 / 100) if brightness else None
@ -227,7 +227,8 @@ class BondLight(BondBaseLight, BondEntity, LightEntity):
class BondDownLight(BondBaseLight, BondEntity, LightEntity): class BondDownLight(BondBaseLight, BondEntity, LightEntity):
"""Representation of a Bond light.""" """Representation of a Bond light."""
def _apply_state(self, state: dict) -> None: def _apply_state(self) -> None:
state = self._device.state
self._attr_is_on = bool(state.get("down_light") and state.get("light")) self._attr_is_on = bool(state.get("down_light") and state.get("light"))
async def async_turn_on(self, **kwargs: Any) -> None: async def async_turn_on(self, **kwargs: Any) -> None:
@ -246,7 +247,8 @@ class BondDownLight(BondBaseLight, BondEntity, LightEntity):
class BondUpLight(BondBaseLight, BondEntity, LightEntity): class BondUpLight(BondBaseLight, BondEntity, LightEntity):
"""Representation of a Bond light.""" """Representation of a Bond light."""
def _apply_state(self, state: dict) -> None: def _apply_state(self) -> None:
state = self._device.state
self._attr_is_on = bool(state.get("up_light") and state.get("light")) self._attr_is_on = bool(state.get("up_light") and state.get("light"))
async def async_turn_on(self, **kwargs: Any) -> None: async def async_turn_on(self, **kwargs: Any) -> None:
@ -268,7 +270,8 @@ class BondFireplace(BondEntity, LightEntity):
_attr_color_mode = ColorMode.BRIGHTNESS _attr_color_mode = ColorMode.BRIGHTNESS
_attr_supported_color_modes = {ColorMode.BRIGHTNESS} _attr_supported_color_modes = {ColorMode.BRIGHTNESS}
def _apply_state(self, state: dict) -> None: def _apply_state(self) -> None:
state = self._device.state
power = state.get("power") power = state.get("power")
flame = state.get("flame") flame = state.get("flame")
self._attr_is_on = power == 1 self._attr_is_on = power == 1

View File

@ -12,7 +12,6 @@ from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.exceptions import HomeAssistantError from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers import config_validation as cv, entity_platform from homeassistant.helpers import config_validation as cv, entity_platform
from homeassistant.helpers.entity import Entity
from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.entity_platform import AddEntitiesCallback
from .const import ( from .const import (
@ -36,27 +35,24 @@ async def async_setup_entry(
hub: BondHub = data[HUB] hub: BondHub = data[HUB]
bpup_subs: BPUPSubscriptions = data[BPUP_SUBS] bpup_subs: BPUPSubscriptions = data[BPUP_SUBS]
platform = entity_platform.async_get_current_platform() platform = entity_platform.async_get_current_platform()
switches: list[Entity] = [
BondSwitch(hub, device, bpup_subs)
for device in hub.devices
if DeviceType.is_generic(device.type)
]
platform.async_register_entity_service( platform.async_register_entity_service(
SERVICE_SET_POWER_TRACKED_STATE, SERVICE_SET_POWER_TRACKED_STATE,
{vol.Required(ATTR_POWER_STATE): cv.boolean}, {vol.Required(ATTR_POWER_STATE): cv.boolean},
"async_set_power_belief", "async_set_power_belief",
) )
async_add_entities(switches, True) async_add_entities(
BondSwitch(hub, device, bpup_subs)
for device in hub.devices
if DeviceType.is_generic(device.type)
)
class BondSwitch(BondEntity, SwitchEntity): class BondSwitch(BondEntity, SwitchEntity):
"""Representation of a Bond generic device.""" """Representation of a Bond generic device."""
def _apply_state(self, state: dict) -> None: def _apply_state(self) -> None:
self._attr_is_on = state.get("power") == 1 self._attr_is_on = self._device.state.get("power") == 1
async def async_turn_on(self, **kwargs: Any) -> None: async def async_turn_on(self, **kwargs: Any) -> None:
"""Turn the device on.""" """Turn the device on."""

View File

@ -20,11 +20,16 @@ class BondDevice:
"""Helper device class to hold ID and attributes together.""" """Helper device class to hold ID and attributes together."""
def __init__( def __init__(
self, device_id: str, attrs: dict[str, Any], props: dict[str, Any] self,
device_id: str,
attrs: dict[str, Any],
props: dict[str, Any],
state: dict[str, Any],
) -> None: ) -> None:
"""Create a helper device from ID and attributes returned by API.""" """Create a helper device from ID and attributes returned by API."""
self.device_id = device_id self.device_id = device_id
self.props = props self.props = props
self.state = state
self._attrs = attrs or {} self._attrs = attrs or {}
self._supported_actions: set[str] = set(self._attrs.get("actions", [])) self._supported_actions: set[str] = set(self._attrs.get("actions", []))
@ -34,6 +39,7 @@ class BondDevice:
"device_id": self.device_id, "device_id": self.device_id,
"props": self.props, "props": self.props,
"attrs": self._attrs, "attrs": self._attrs,
"state": self.state,
}.__repr__() }.__repr__()
@property @property
@ -150,7 +156,11 @@ class BondHub:
break break
setup_device_ids.append(device_id) setup_device_ids.append(device_id)
tasks.extend( tasks.extend(
[self.bond.device(device_id), self.bond.device_properties(device_id)] [
self.bond.device(device_id),
self.bond.device_properties(device_id),
self.bond.device_state(device_id),
]
) )
responses = await gather_with_concurrency(MAX_REQUESTS, *tasks) responses = await gather_with_concurrency(MAX_REQUESTS, *tasks)
@ -158,10 +168,13 @@ class BondHub:
for device_id in setup_device_ids: for device_id in setup_device_ids:
self._devices.append( self._devices.append(
BondDevice( BondDevice(
device_id, responses[response_idx], responses[response_idx + 1] device_id,
responses[response_idx],
responses[response_idx + 1],
responses[response_idx + 2],
) )
) )
response_idx += 2 response_idx += 3
_LOGGER.debug("Discovered Bond devices: %s", self._devices) _LOGGER.debug("Discovered Bond devices: %s", self._devices)
try: try:

View File

@ -18,6 +18,7 @@ from .common import (
patch_bond_device, patch_bond_device,
patch_bond_device_ids, patch_bond_device_ids,
patch_bond_device_properties, patch_bond_device_properties,
patch_bond_device_state,
patch_bond_token, patch_bond_token,
patch_bond_version, patch_bond_version,
) )
@ -38,7 +39,7 @@ async def test_user_form(hass: core.HomeAssistant):
return_value={"bondid": "ZXXX12345"} return_value={"bondid": "ZXXX12345"}
), patch_bond_device_ids( ), patch_bond_device_ids(
return_value=["f6776c11", "f6776c12"] return_value=["f6776c11", "f6776c12"]
), patch_bond_bridge(), patch_bond_device_properties(), patch_bond_device(), _patch_async_setup_entry() as mock_setup_entry: ), patch_bond_bridge(), patch_bond_device_properties(), patch_bond_device(), patch_bond_device_state(), _patch_async_setup_entry() as mock_setup_entry:
result2 = await hass.config_entries.flow.async_configure( result2 = await hass.config_entries.flow.async_configure(
result["flow_id"], result["flow_id"],
{CONF_HOST: "some host", CONF_ACCESS_TOKEN: "test-token"}, {CONF_HOST: "some host", CONF_ACCESS_TOKEN: "test-token"},
@ -73,7 +74,7 @@ async def test_user_form_with_non_bridge(hass: core.HomeAssistant):
} }
), patch_bond_bridge( ), patch_bond_bridge(
return_value={} return_value={}
), _patch_async_setup_entry() as mock_setup_entry: ), patch_bond_device_state(), _patch_async_setup_entry() as mock_setup_entry:
result2 = await hass.config_entries.flow.async_configure( result2 = await hass.config_entries.flow.async_configure(
result["flow_id"], result["flow_id"],
{CONF_HOST: "some host", CONF_ACCESS_TOKEN: "test-token"}, {CONF_HOST: "some host", CONF_ACCESS_TOKEN: "test-token"},