1 """An abstract class common to all Bond entities."""
3 from __future__
import annotations
5 from abc
import abstractmethod
6 from asyncio
import Lock
7 from datetime
import datetime
10 from aiohttp
import ClientError
25 from .const
import DOMAIN
26 from .models
import BondData
27 from .utils
import BondDevice
29 _LOGGER = logging.getLogger(__name__)
31 _FALLBACK_SCAN_INTERVAL = 10
32 _BPUP_ALIVE_SCAN_INTERVAL = 60
36 """Generic Bond entity encapsulating common features of any Bond controlled device."""
38 _attr_should_poll =
False
44 sub_device: str |
None =
None,
45 sub_device_id: str |
None =
None,
47 """Initialize entity with API and device info."""
59 sub_device_id = f
"_{sub_device_id}"
61 sub_device_id = f
"_{sub_device}"
64 self.
_attr_unique_id_attr_unique_id = f
"{hub.bond_id}_{device.device_id}{sub_device_id}"
66 sub_device_name = sub_device.replace(
"_",
" ").title()
67 self.
_attr_name_attr_name = f
"{device.name} {sub_device_name}"
79 """Get a an HA device representing this Bond controlled device."""
81 manufacturer=self.
_hub_hub.make,
83 identifiers={(DOMAIN, self.
_hub_hub.bond_id, self.
_device_id_device_id)},
84 configuration_url=f
"http://{self._hub.host}",
86 if self.
namename
is not None:
87 device_info[ATTR_NAME] = self.
_device_device.name
88 if self.
_hub_hub.bond_id
is not None:
89 device_info[ATTR_VIA_DEVICE] = (DOMAIN, self.
_hub_hub.bond_id)
90 if self.
_device_device.location
is not None:
91 device_info[ATTR_SUGGESTED_AREA] = self.
_device_device.location
92 if not self.
_hub_hub.is_bridge:
93 if self.
_hub_hub.model
is not None:
94 device_info[ATTR_MODEL] = self.
_hub_hub.model
95 if self.
_hub_hub.fw_ver
is not None:
96 device_info[ATTR_SW_VERSION] = self.
_hub_hub.fw_ver
97 if self.
_hub_hub.mcu_ver
is not None:
98 device_info[ATTR_HW_VERSION] = self.
_hub_hub.mcu_ver
101 if self.
_device_device.branding_profile:
102 model_data.append(self.
_device_device.branding_profile)
103 if self.
_device_device.template:
104 model_data.append(self.
_device_device.template)
106 device_info[ATTR_MODEL] =
" ".join(model_data)
111 """Perform a manual update from API."""
116 """Fetch via the API if BPUP is not alive."""
119 self.
hasshass.is_stopping
127 "Updating %s took longer than the scheduled update interval %s",
129 _FALLBACK_SCAN_INTERVAL,
132 self.
hasshass.async_create_background_task(
133 self.
_async_update_async_update(), f
"{DOMAIN} {self.name} update", eager_start=
True
137 """Fetch via the API."""
143 """Fetch via the API."""
145 state: dict = await self.
_bond_bond.device_state(self.
_device_id_device_id)
146 except (ClientError, TimeoutError, OSError)
as error:
149 "Entity %s has become unavailable", self.
entity_identity_id, exc_info=error
157 raise NotImplementedError
161 """Process a state change."""
164 _LOGGER.info(
"Entity %s has come back", self.
entity_identity_id)
167 "Device state for %s (%s) is:\n%s", self.
namename, self.
entity_identity_id, state
169 self.
_device_device.state = state
174 """Process a state change from BPUP."""
175 topic = json_msg[
"t"]
176 if topic != f
"devices/{self._device_id}/state":
183 """Subscribe to BPUP and start polling."""
190 """Schedule the BPUP alive or poll."""
194 _BPUP_ALIVE_SCAN_INTERVAL
if alive
else _FALLBACK_SCAN_INTERVAL,
199 """Unsubscribe from BPUP data on remove."""
_async_update_if_bpup_not_alive_job
None _async_update_if_bpup_not_alive(self, datetime now)
DeviceInfo device_info(self)
None async_added_to_hass(self)
None _async_update_from_api(self)
None _async_bpup_callback(self, dict json_msg)
None __init__(self, BondData data, BondDevice device, str|None sub_device=None, str|None sub_device_id=None)
None _async_state_callback(self, dict state)
None _async_schedule_bpup_alive_or_poll(self)
None async_will_remove_from_hass(self)
None async_write_ha_state(self)
str|UndefinedType|None name(self)
Callable[[], None] subscribe(HomeAssistant hass, str topic, MessageCallbackType msg_callback, int qos=DEFAULT_QOS, str encoding="utf-8")
CALLBACK_TYPE async_call_later(HomeAssistant hass, float|timedelta delay, HassJob[[datetime], Coroutine[Any, Any, None]|None]|Callable[[datetime], Coroutine[Any, Any, None]|None] action)