Add Shelly Gen2 polling for sesnors missing push updates (#64171)
This commit is contained in:
parent
b66fd820ff
commit
601f3f9c6d
4 changed files with 79 additions and 9 deletions
|
@ -53,7 +53,9 @@ from .const import (
|
|||
REST_SENSORS_UPDATE_INTERVAL,
|
||||
RPC,
|
||||
RPC_INPUTS_EVENTS_TYPES,
|
||||
RPC_POLL,
|
||||
RPC_RECONNECT_INTERVAL,
|
||||
RPC_SENSORS_POLLING_INTERVAL,
|
||||
SHBTN_MODELS,
|
||||
SLEEP_PERIOD_MULTIPLIER,
|
||||
UPDATE_PERIOD_MULTIPLIER,
|
||||
|
@ -253,6 +255,10 @@ async def async_setup_rpc_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool
|
|||
] = RpcDeviceWrapper(hass, entry, device)
|
||||
device_wrapper.async_setup()
|
||||
|
||||
hass.data[DOMAIN][DATA_CONFIG_ENTRY][entry.entry_id][RPC_POLL] = RpcPollingWrapper(
|
||||
hass, entry, device
|
||||
)
|
||||
|
||||
hass.config_entries.async_setup_platforms(entry, RPC_PLATFORMS)
|
||||
|
||||
return True
|
||||
|
@ -768,3 +774,45 @@ class RpcDeviceWrapper(update_coordinator.DataUpdateCoordinator):
|
|||
"""Handle Home Assistant stopping."""
|
||||
_LOGGER.debug("Stopping RpcDeviceWrapper for %s", self.name)
|
||||
await self.shutdown()
|
||||
|
||||
|
||||
class RpcPollingWrapper(update_coordinator.DataUpdateCoordinator):
|
||||
"""Polling Wrapper for a Shelly RPC based device."""
|
||||
|
||||
def __init__(
|
||||
self, hass: HomeAssistant, entry: ConfigEntry, device: RpcDevice
|
||||
) -> None:
|
||||
"""Initialize the RPC polling coordinator."""
|
||||
self.device_id: str | None = None
|
||||
|
||||
device_name = get_rpc_device_name(device) if device.initialized else entry.title
|
||||
super().__init__(
|
||||
hass,
|
||||
_LOGGER,
|
||||
name=device_name,
|
||||
update_interval=timedelta(seconds=RPC_SENSORS_POLLING_INTERVAL),
|
||||
)
|
||||
self.entry = entry
|
||||
self.device = device
|
||||
|
||||
async def _async_update_data(self) -> None:
|
||||
"""Fetch data."""
|
||||
if not self.device.connected:
|
||||
raise update_coordinator.UpdateFailed("Device disconnected")
|
||||
|
||||
try:
|
||||
_LOGGER.debug("Polling Shelly RPC Device - %s", self.name)
|
||||
async with async_timeout.timeout(AIOSHELLY_DEVICE_TIMEOUT_SEC):
|
||||
await self.device.update_status()
|
||||
except OSError as err:
|
||||
raise update_coordinator.UpdateFailed("Device disconnected") from err
|
||||
|
||||
@property
|
||||
def model(self) -> str:
|
||||
"""Model of the device."""
|
||||
return cast(str, self.entry.data["model"])
|
||||
|
||||
@property
|
||||
def mac(self) -> str:
|
||||
"""Mac address of the device."""
|
||||
return cast(str, self.entry.unique_id)
|
||||
|
|
|
@ -10,6 +10,7 @@ DEVICE: Final = "device"
|
|||
DOMAIN: Final = "shelly"
|
||||
REST: Final = "rest"
|
||||
RPC: Final = "rpc"
|
||||
RPC_POLL: Final = "rpc_poll"
|
||||
|
||||
CONF_COAP_PORT: Final = "coap_port"
|
||||
DEFAULT_COAP_PORT: Final = 5683
|
||||
|
@ -53,6 +54,9 @@ POLLING_TIMEOUT_SEC: Final = 18
|
|||
# Refresh interval for REST sensors
|
||||
REST_SENSORS_UPDATE_INTERVAL: Final = 60
|
||||
|
||||
# Refresh interval for RPC polling sensors
|
||||
RPC_SENSORS_POLLING_INTERVAL: Final = 60
|
||||
|
||||
# Timeout used for aioshelly calls
|
||||
AIOSHELLY_DEVICE_TIMEOUT_SEC: Final = 10
|
||||
|
||||
|
|
|
@ -24,7 +24,12 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
|||
from homeassistant.helpers.restore_state import RestoreEntity
|
||||
from homeassistant.helpers.typing import StateType
|
||||
|
||||
from . import BlockDeviceWrapper, RpcDeviceWrapper, ShellyDeviceRestWrapper
|
||||
from . import (
|
||||
BlockDeviceWrapper,
|
||||
RpcDeviceWrapper,
|
||||
RpcPollingWrapper,
|
||||
ShellyDeviceRestWrapper,
|
||||
)
|
||||
from .const import (
|
||||
AIOSHELLY_DEVICE_TIMEOUT_SEC,
|
||||
BLOCK,
|
||||
|
@ -32,6 +37,7 @@ from .const import (
|
|||
DOMAIN,
|
||||
REST,
|
||||
RPC,
|
||||
RPC_POLL,
|
||||
)
|
||||
from .utils import (
|
||||
async_remove_shelly_entity,
|
||||
|
@ -160,6 +166,10 @@ async def async_setup_entry_rpc(
|
|||
config_entry.entry_id
|
||||
][RPC]
|
||||
|
||||
polling_wrapper: RpcPollingWrapper = hass.data[DOMAIN][DATA_CONFIG_ENTRY][
|
||||
config_entry.entry_id
|
||||
][RPC_POLL]
|
||||
|
||||
entities = []
|
||||
for sensor_id in sensors:
|
||||
description = sensors[sensor_id]
|
||||
|
@ -178,17 +188,17 @@ async def async_setup_entry_rpc(
|
|||
unique_id = f"{wrapper.mac}-{key}-{sensor_id}"
|
||||
await async_remove_shelly_entity(hass, domain, unique_id)
|
||||
else:
|
||||
entities.append((key, sensor_id, description))
|
||||
if description.should_poll:
|
||||
entities.append(
|
||||
sensor_class(polling_wrapper, key, sensor_id, description)
|
||||
)
|
||||
else:
|
||||
entities.append(sensor_class(wrapper, key, sensor_id, description))
|
||||
|
||||
if not entities:
|
||||
return
|
||||
|
||||
async_add_entities(
|
||||
[
|
||||
sensor_class(wrapper, key, sensor_id, description)
|
||||
for key, sensor_id, description in entities
|
||||
]
|
||||
)
|
||||
async_add_entities(entities)
|
||||
|
||||
|
||||
async def async_setup_entry_rest(
|
||||
|
@ -257,6 +267,7 @@ class RpcAttributeDescription:
|
|||
removal_condition: Callable[[dict, str], bool] | None = None
|
||||
extra_state_attributes: Callable[[dict, dict], dict | None] | None = None
|
||||
entity_category: EntityCategory | None = None
|
||||
should_poll: bool = False
|
||||
|
||||
|
||||
@dataclass
|
||||
|
@ -343,7 +354,11 @@ class ShellyBlockEntity(entity.Entity):
|
|||
class ShellyRpcEntity(entity.Entity):
|
||||
"""Helper class to represent a rpc entity."""
|
||||
|
||||
def __init__(self, wrapper: RpcDeviceWrapper, key: str) -> None:
|
||||
def __init__(
|
||||
self,
|
||||
wrapper: RpcDeviceWrapper | RpcPollingWrapper,
|
||||
key: str,
|
||||
) -> None:
|
||||
"""Initialize Shelly entity."""
|
||||
self.wrapper = wrapper
|
||||
self.key = key
|
||||
|
|
|
@ -287,6 +287,7 @@ RPC_SENSORS: Final = {
|
|||
state_class=SensorStateClass.MEASUREMENT,
|
||||
default_enabled=False,
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
should_poll=True,
|
||||
),
|
||||
"rssi": RpcAttributeDescription(
|
||||
key="wifi",
|
||||
|
@ -297,6 +298,7 @@ RPC_SENSORS: Final = {
|
|||
state_class=SensorStateClass.MEASUREMENT,
|
||||
default_enabled=False,
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
should_poll=True,
|
||||
),
|
||||
"uptime": RpcAttributeDescription(
|
||||
key="sys",
|
||||
|
@ -306,6 +308,7 @@ RPC_SENSORS: Final = {
|
|||
device_class=SensorDeviceClass.TIMESTAMP,
|
||||
default_enabled=False,
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
should_poll=True,
|
||||
),
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue