Move add/remove logic of deCONZ clip sensors to gateway class (#74481)

This commit is contained in:
Robert Svensson 2022-07-09 23:35:06 +02:00 committed by GitHub
parent d33779d3a0
commit e3242d8d16
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 60 additions and 81 deletions

View file

@ -24,7 +24,6 @@ from homeassistant.components.binary_sensor import (
from homeassistant.config_entries import ConfigEntry from homeassistant.config_entries import ConfigEntry
from homeassistant.const import ATTR_TEMPERATURE from homeassistant.const import ATTR_TEMPERATURE
from homeassistant.core import HomeAssistant, callback from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.helpers.entity import EntityCategory from homeassistant.helpers.entity import EntityCategory
from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.entity_platform import AddEntitiesCallback
import homeassistant.helpers.entity_registry as er import homeassistant.helpers.entity_registry as er
@ -215,9 +214,6 @@ async def async_setup_entry(
"""Add sensor from deCONZ.""" """Add sensor from deCONZ."""
sensor = gateway.api.sensors[sensor_id] sensor = gateway.api.sensors[sensor_id]
if not gateway.option_allow_clip_sensor and sensor.type.startswith("CLIP"):
return
for description in ( for description in (
ENTITY_DESCRIPTIONS.get(type(sensor), []) + BINARY_SENSOR_DESCRIPTIONS ENTITY_DESCRIPTIONS.get(type(sensor), []) + BINARY_SENSOR_DESCRIPTIONS
): ):
@ -236,21 +232,6 @@ async def async_setup_entry(
gateway.api.sensors, gateway.api.sensors,
) )
@callback
def async_reload_clip_sensors() -> None:
"""Load clip sensor sensors from deCONZ."""
for sensor_id, sensor in gateway.api.sensors.items():
if sensor.type.startswith("CLIP"):
async_add_sensor(EventType.ADDED, sensor_id)
config_entry.async_on_unload(
async_dispatcher_connect(
hass,
gateway.signal_reload_clip_sensors,
async_reload_clip_sensors,
)
)
class DeconzBinarySensor(DeconzDevice, BinarySensorEntity): class DeconzBinarySensor(DeconzDevice, BinarySensorEntity):
"""Representation of a deCONZ binary sensor.""" """Representation of a deCONZ binary sensor."""

View file

@ -28,7 +28,6 @@ from homeassistant.components.climate.const import (
from homeassistant.config_entries import ConfigEntry from homeassistant.config_entries import ConfigEntry
from homeassistant.const import ATTR_TEMPERATURE, TEMP_CELSIUS from homeassistant.const import ATTR_TEMPERATURE, TEMP_CELSIUS
from homeassistant.core import HomeAssistant, callback from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.entity_platform import AddEntitiesCallback
from .const import ATTR_LOCKED, ATTR_OFFSET, ATTR_VALVE from .const import ATTR_LOCKED, ATTR_OFFSET, ATTR_VALVE
@ -85,8 +84,6 @@ async def async_setup_entry(
def async_add_climate(_: EventType, climate_id: str) -> None: def async_add_climate(_: EventType, climate_id: str) -> None:
"""Add climate from deCONZ.""" """Add climate from deCONZ."""
climate = gateway.api.sensors.thermostat[climate_id] climate = gateway.api.sensors.thermostat[climate_id]
if not gateway.option_allow_clip_sensor and climate.type.startswith("CLIP"):
return
async_add_entities([DeconzThermostat(climate, gateway)]) async_add_entities([DeconzThermostat(climate, gateway)])
gateway.register_platform_add_device_callback( gateway.register_platform_add_device_callback(
@ -94,21 +91,6 @@ async def async_setup_entry(
gateway.api.sensors.thermostat, gateway.api.sensors.thermostat,
) )
@callback
def async_reload_clip_sensors() -> None:
"""Load clip sensors from deCONZ."""
for climate_id, climate in gateway.api.sensors.thermostat.items():
if climate.type.startswith("CLIP"):
async_add_climate(EventType.ADDED, climate_id)
config_entry.async_on_unload(
async_dispatcher_connect(
hass,
gateway.signal_reload_clip_sensors,
async_reload_clip_sensors,
)
)
class DeconzThermostat(DeconzDevice, ClimateEntity): class DeconzThermostat(DeconzDevice, ClimateEntity):
"""Representation of a deCONZ thermostat.""" """Representation of a deCONZ thermostat."""

View file

@ -46,9 +46,6 @@ async def async_setup_events(gateway: DeconzGateway) -> None:
new_event: DeconzAlarmEvent | DeconzEvent new_event: DeconzAlarmEvent | DeconzEvent
sensor = gateway.api.sensors[sensor_id] sensor = gateway.api.sensors[sensor_id]
if not gateway.option_allow_clip_sensor and sensor.type.startswith("CLIP"):
return None
if isinstance(sensor, Switch): if isinstance(sensor, Switch):
new_event = DeconzEvent(sensor, gateway) new_event = DeconzEvent(sensor, gateway)

View file

@ -9,6 +9,7 @@ from typing import TYPE_CHECKING, Any, cast
import async_timeout import async_timeout
from pydeconz import DeconzSession, errors from pydeconz import DeconzSession, errors
from pydeconz.interfaces import sensors
from pydeconz.interfaces.api import APIItems, GroupedAPIItems from pydeconz.interfaces.api import APIItems, GroupedAPIItems
from pydeconz.interfaces.groups import Groups from pydeconz.interfaces.groups import Groups
from pydeconz.models.event import EventType from pydeconz.models.event import EventType
@ -42,6 +43,35 @@ from .errors import AuthenticationRequired, CannotConnect
if TYPE_CHECKING: if TYPE_CHECKING:
from .deconz_event import DeconzAlarmEvent, DeconzEvent from .deconz_event import DeconzAlarmEvent, DeconzEvent
SENSORS = (
sensors.SensorResourceManager,
sensors.AirPurifierHandler,
sensors.AirQualityHandler,
sensors.AlarmHandler,
sensors.AncillaryControlHandler,
sensors.BatteryHandler,
sensors.CarbonMonoxideHandler,
sensors.ConsumptionHandler,
sensors.DaylightHandler,
sensors.DoorLockHandler,
sensors.FireHandler,
sensors.GenericFlagHandler,
sensors.GenericStatusHandler,
sensors.HumidityHandler,
sensors.LightLevelHandler,
sensors.OpenCloseHandler,
sensors.PowerHandler,
sensors.PresenceHandler,
sensors.PressureHandler,
sensors.RelativeRotaryHandler,
sensors.SwitchHandler,
sensors.TemperatureHandler,
sensors.ThermostatHandler,
sensors.TimeHandler,
sensors.VibrationHandler,
sensors.WaterHandler,
)
class DeconzGateway: class DeconzGateway:
"""Manages a single deCONZ gateway.""" """Manages a single deCONZ gateway."""
@ -60,14 +90,17 @@ class DeconzGateway:
self.ignore_state_updates = False self.ignore_state_updates = False
self.signal_reachable = f"deconz-reachable-{config_entry.entry_id}" self.signal_reachable = f"deconz-reachable-{config_entry.entry_id}"
self.signal_reload_clip_sensors = f"deconz_reload_clip_{config_entry.entry_id}"
self.deconz_ids: dict[str, str] = {} self.deconz_ids: dict[str, str] = {}
self.entities: dict[str, set[str]] = {} self.entities: dict[str, set[str]] = {}
self.events: list[DeconzAlarmEvent | DeconzEvent] = [] self.events: list[DeconzAlarmEvent | DeconzEvent] = []
self.ignored_devices: set[tuple[Callable[[EventType, str], None], str]] = set() self.clip_sensors: set[tuple[Callable[[EventType, str], None], str]] = set()
self.deconz_groups: set[tuple[Callable[[EventType, str], None], str]] = set() self.deconz_groups: set[tuple[Callable[[EventType, str], None], str]] = set()
self.ignored_devices: set[tuple[Callable[[EventType, str], None], str]] = set()
self.option_allow_clip_sensor = self.config_entry.options.get(
CONF_ALLOW_CLIP_SENSOR, DEFAULT_ALLOW_CLIP_SENSOR
)
self.option_allow_deconz_groups = config_entry.options.get( self.option_allow_deconz_groups = config_entry.options.get(
CONF_ALLOW_DECONZ_GROUPS, DEFAULT_ALLOW_DECONZ_GROUPS CONF_ALLOW_DECONZ_GROUPS, DEFAULT_ALLOW_DECONZ_GROUPS
) )
@ -90,20 +123,12 @@ class DeconzGateway:
"""Gateway which is used with deCONZ services without defining id.""" """Gateway which is used with deCONZ services without defining id."""
return cast(bool, self.config_entry.options[CONF_MASTER_GATEWAY]) return cast(bool, self.config_entry.options[CONF_MASTER_GATEWAY])
# Options
@property
def option_allow_clip_sensor(self) -> bool:
"""Allow loading clip sensor from gateway."""
return self.config_entry.options.get(
CONF_ALLOW_CLIP_SENSOR, DEFAULT_ALLOW_CLIP_SENSOR
)
@callback @callback
def register_platform_add_device_callback( def register_platform_add_device_callback(
self, self,
add_device_callback: Callable[[EventType, str], None], add_device_callback: Callable[[EventType, str], None],
deconz_device_interface: APIItems | GroupedAPIItems, deconz_device_interface: APIItems | GroupedAPIItems,
always_ignore_clip_sensors: bool = False,
) -> None: ) -> None:
"""Wrap add_device_callback to check allow_new_devices option.""" """Wrap add_device_callback to check allow_new_devices option."""
@ -128,6 +153,13 @@ class DeconzGateway:
if not self.option_allow_deconz_groups: if not self.option_allow_deconz_groups:
return return
if isinstance(deconz_device_interface, SENSORS):
device = deconz_device_interface[device_id]
if device.type.startswith("CLIP") and not always_ignore_clip_sensors:
self.clip_sensors.add((async_add_device, device_id))
if not self.option_allow_clip_sensor:
return
add_device_callback(EventType.ADDED, device_id) add_device_callback(EventType.ADDED, device_id)
self.config_entry.async_on_unload( self.config_entry.async_on_unload(
@ -212,15 +244,20 @@ class DeconzGateway:
# Allow CLIP sensors # Allow CLIP sensors
if self.option_allow_clip_sensor: option_allow_clip_sensor = self.config_entry.options.get(
async_dispatcher_send(self.hass, self.signal_reload_clip_sensors) CONF_ALLOW_CLIP_SENSOR, DEFAULT_ALLOW_CLIP_SENSOR
)
else: if option_allow_clip_sensor != self.option_allow_clip_sensor:
deconz_ids += [ self.option_allow_clip_sensor = option_allow_clip_sensor
sensor.deconz_id if option_allow_clip_sensor:
for sensor in self.api.sensors.values() for add_device, device_id in self.clip_sensors:
if sensor.type.startswith("CLIP") add_device(EventType.ADDED, device_id)
] else:
deconz_ids += [
sensor.deconz_id
for sensor in self.api.sensors.values()
if sensor.type.startswith("CLIP")
]
# Allow Groups # Allow Groups

View file

@ -46,6 +46,7 @@ async def async_setup_entry(
gateway.register_platform_add_device_callback( gateway.register_platform_add_device_callback(
async_add_lock_from_sensor, async_add_lock_from_sensor,
gateway.api.sensors.door_lock, gateway.api.sensors.door_lock,
always_ignore_clip_sensors=True,
) )

View file

@ -65,8 +65,7 @@ async def async_setup_entry(
def async_add_sensor(_: EventType, sensor_id: str) -> None: def async_add_sensor(_: EventType, sensor_id: str) -> None:
"""Add sensor from deCONZ.""" """Add sensor from deCONZ."""
sensor = gateway.api.sensors.presence[sensor_id] sensor = gateway.api.sensors.presence[sensor_id]
if sensor.type.startswith("CLIP"):
return
for description in ENTITY_DESCRIPTIONS.get(type(sensor), []): for description in ENTITY_DESCRIPTIONS.get(type(sensor), []):
if ( if (
not hasattr(sensor, description.key) not hasattr(sensor, description.key)
@ -78,6 +77,7 @@ async def async_setup_entry(
gateway.register_platform_add_device_callback( gateway.register_platform_add_device_callback(
async_add_sensor, async_add_sensor,
gateway.api.sensors.presence, gateway.api.sensors.presence,
always_ignore_clip_sensors=True,
) )

View file

@ -39,7 +39,6 @@ from homeassistant.const import (
TEMP_CELSIUS, TEMP_CELSIUS,
) )
from homeassistant.core import HomeAssistant, callback from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.helpers.entity import EntityCategory from homeassistant.helpers.entity import EntityCategory
from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.typing import StateType from homeassistant.helpers.typing import StateType
@ -248,9 +247,6 @@ async def async_setup_entry(
sensor = gateway.api.sensors[sensor_id] sensor = gateway.api.sensors[sensor_id]
entities: list[DeconzSensor] = [] entities: list[DeconzSensor] = []
if not gateway.option_allow_clip_sensor and sensor.type.startswith("CLIP"):
return
if sensor.battery is None and not sensor.type.startswith("CLIP"): if sensor.battery is None and not sensor.type.startswith("CLIP"):
DeconzBatteryTracker(sensor_id, gateway, async_add_entities) DeconzBatteryTracker(sensor_id, gateway, async_add_entities)
@ -276,21 +272,6 @@ async def async_setup_entry(
gateway.api.sensors, gateway.api.sensors,
) )
@callback
def async_reload_clip_sensors() -> None:
"""Load clip sensor sensors from deCONZ."""
for sensor_id, sensor in gateway.api.sensors.items():
if sensor.type.startswith("CLIP"):
async_add_sensor(EventType.ADDED, sensor_id)
config_entry.async_on_unload(
async_dispatcher_connect(
hass,
gateway.signal_reload_clip_sensors,
async_reload_clip_sensors,
)
)
class DeconzSensor(DeconzDevice, SensorEntity): class DeconzSensor(DeconzDevice, SensorEntity):
"""Representation of a deCONZ sensor.""" """Representation of a deCONZ sensor."""