Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion homeassistant/components/deconz/alarm_control_panel.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ def async_add_sensor(_: EventType, sensor_id: str) -> None:

config_entry.async_on_unload(
gateway.api.sensors.ancillary_control.subscribe(
async_add_sensor,
gateway.evaluate_add_device(async_add_sensor),
EventType.ADDED,
)
)
Expand Down
63 changes: 32 additions & 31 deletions homeassistant/components/deconz/binary_sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from dataclasses import dataclass

from pydeconz.interfaces.sensors import SensorResources
from pydeconz.models.event import EventType
from pydeconz.models.sensor.alarm import Alarm
from pydeconz.models.sensor.carbon_monoxide import CarbonMonoxide
from pydeconz.models.sensor.fire import Fire
Expand Down Expand Up @@ -188,48 +189,48 @@ async def async_setup_entry(
gateway.entities[DOMAIN] = set()

@callback
def async_add_sensor(sensors: list[SensorResources] | None = None) -> None:
"""Add binary sensor from deCONZ."""
entities: list[DeconzBinarySensor] = []

if sensors is None:
sensors = gateway.api.sensors.values()

for sensor in sensors:

if not gateway.option_allow_clip_sensor and sensor.type.startswith("CLIP"):
continue

known_entities = set(gateway.entities[DOMAIN])
for description in (
ENTITY_DESCRIPTIONS.get(type(sensor), []) + BINARY_SENSOR_DESCRIPTIONS
def async_add_sensor(_: EventType, sensor_id: str) -> None:
"""Add sensor from deCONZ."""
sensor = gateway.api.sensors[sensor_id]

if not gateway.option_allow_clip_sensor and sensor.type.startswith("CLIP"):
return

for description in (
ENTITY_DESCRIPTIONS.get(type(sensor), []) + BINARY_SENSOR_DESCRIPTIONS
):
if (
not hasattr(sensor, description.key)
or description.value_fn(sensor) is None
):
continue

if (
not hasattr(sensor, description.key)
or description.value_fn(sensor) is None
):
continue
async_add_entities([DeconzBinarySensor(sensor, gateway, description)])

new_sensor = DeconzBinarySensor(sensor, gateway, description)
if new_sensor.unique_id not in known_entities:
entities.append(new_sensor)
config_entry.async_on_unload(
gateway.api.sensors.subscribe(
gateway.evaluate_add_device(async_add_sensor),
EventType.ADDED,
)
)
for sensor_id in gateway.api.sensors:
async_add_sensor(EventType.ADDED, sensor_id)

if entities:
async_add_entities(entities)
@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_new_sensor,
async_add_sensor,
gateway.signal_reload_clip_sensors,
async_reload_clip_sensors,
)
)

async_add_sensor(
[gateway.api.sensors[key] for key in sorted(gateway.api.sensors, key=int)]
)


class DeconzBinarySensor(DeconzDevice, BinarySensorEntity):
"""Representation of a deCONZ binary sensor."""
Expand Down
4 changes: 2 additions & 2 deletions homeassistant/components/deconz/climate.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ def async_add_climate(_: EventType, climate_id: str) -> None:

config_entry.async_on_unload(
gateway.api.sensors.thermostat.subscribe(
async_add_climate,
gateway.evaluate_add_device(async_add_climate),
EventType.ADDED,
)
)
Expand All @@ -115,7 +115,7 @@ def async_add_climate(_: EventType, climate_id: str) -> None:

@callback
def async_reload_clip_sensors() -> None:
"""Load clip climate sensors from deCONZ."""
"""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)
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/deconz/cover.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ def async_add_cover(_: EventType, cover_id: str) -> None:

config_entry.async_on_unload(
gateway.api.lights.covers.subscribe(
async_add_cover,
gateway.evaluate_add_device(async_add_cover),
EventType.ADDED,
)
)
Expand Down
4 changes: 2 additions & 2 deletions homeassistant/components/deconz/deconz_event.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,14 +66,14 @@ def async_add_sensor(_: EventType, sensor_id: str) -> None:

gateway.config_entry.async_on_unload(
gateway.api.sensors.ancillary_control.subscribe(
async_add_sensor,
gateway.evaluate_add_device(async_add_sensor),
EventType.ADDED,
)
)

gateway.config_entry.async_on_unload(
gateway.api.sensors.switch.subscribe(
async_add_sensor,
gateway.evaluate_add_device(async_add_sensor),
EventType.ADDED,
)
)
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/deconz/fan.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ def async_add_fan(_: EventType, fan_id: str) -> None:

config_entry.async_on_unload(
gateway.api.lights.fans.subscribe(
async_add_fan,
gateway.evaluate_add_device(async_add_fan),
EventType.ADDED,
)
)
Expand Down
45 changes: 39 additions & 6 deletions homeassistant/components/deconz/gateway.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,15 @@
from __future__ import annotations

import asyncio
from collections.abc import Callable
from types import MappingProxyType
from typing import TYPE_CHECKING, Any, cast

import async_timeout
from pydeconz import DeconzSession, errors
from pydeconz.models import ResourceGroup
from pydeconz.models.alarm_system import AlarmSystem as DeconzAlarmSystem
from pydeconz.models.event import EventType
from pydeconz.models.group import Group as DeconzGroup
from pydeconz.models.light import LightBase as DeconzLight
from pydeconz.models.sensor import SensorBase as DeconzSensor
Expand Down Expand Up @@ -76,10 +78,14 @@ def __init__(
self.deconz_ids: dict[str, str] = {}
self.entities: dict[str, set[str]] = {}
self.events: list[DeconzAlarmEvent | DeconzEvent] = []
self.ignored_devices: set[tuple[Callable[[EventType, str], None], str]] = set()

self._option_allow_deconz_groups = self.config_entry.options.get(
CONF_ALLOW_DECONZ_GROUPS, DEFAULT_ALLOW_DECONZ_GROUPS
)
self.option_allow_new_devices = self.config_entry.options.get(
CONF_ALLOW_NEW_DEVICES, DEFAULT_ALLOW_NEW_DEVICES
)

@property
def bridgeid(self) -> str:
Expand Down Expand Up @@ -112,12 +118,31 @@ def option_allow_deconz_groups(self) -> bool:
CONF_ALLOW_DECONZ_GROUPS, DEFAULT_ALLOW_DECONZ_GROUPS
)

@property
def option_allow_new_devices(self) -> bool:
"""Allow automatic adding of new devices."""
return self.config_entry.options.get(
CONF_ALLOW_NEW_DEVICES, DEFAULT_ALLOW_NEW_DEVICES
)
@callback
def evaluate_add_device(
self, add_device_callback: Callable[[EventType, str], None]
) -> Callable[[EventType, str], None]:
"""Wrap add_device_callback to check allow_new_devices option."""

def async_add_device(event: EventType, device_id: str) -> None:
"""Add device or add it to ignored_devices set.

If ignore_state_updates is True means device_refresh service is used.
Device_refresh is expected to load new devices.
"""
if not self.option_allow_new_devices and not self.ignore_state_updates:
self.ignored_devices.add((add_device_callback, device_id))
return
add_device_callback(event, device_id)

return async_add_device

@callback
def load_ignored_devices(self) -> None:
"""Load previously ignored devices."""
for add_entities, device_id in self.ignored_devices:
add_entities(EventType.ADDED, device_id)
self.ignored_devices.clear()

# Callbacks

Expand Down Expand Up @@ -230,6 +255,14 @@ async def options_updated(self) -> None:

self._option_allow_deconz_groups = self.option_allow_deconz_groups

option_allow_new_devices = self.config_entry.options.get(
CONF_ALLOW_NEW_DEVICES, DEFAULT_ALLOW_NEW_DEVICES
)
if option_allow_new_devices and not self.option_allow_new_devices:
self.load_ignored_devices()

self.option_allow_new_devices = option_allow_new_devices

entity_registry = er.async_get(self.hass)

for entity_id, deconz_id in self.deconz_ids.items():
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/deconz/light.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ def async_add_light(_: EventType, light_id: str) -> None:

config_entry.async_on_unload(
gateway.api.lights.lights.subscribe(
async_add_light,
gateway.evaluate_add_device(async_add_light),
EventType.ADDED,
)
)
Expand Down
4 changes: 2 additions & 2 deletions homeassistant/components/deconz/lock.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ def async_add_lock_from_light(_: EventType, lock_id: str) -> None:

config_entry.async_on_unload(
gateway.api.lights.locks.subscribe(
async_add_lock_from_light,
gateway.evaluate_add_device(async_add_lock_from_light),
EventType.ADDED,
)
)
Expand All @@ -49,7 +49,7 @@ def async_add_lock_from_sensor(_: EventType, lock_id: str) -> None:

config_entry.async_on_unload(
gateway.api.sensors.door_lock.subscribe(
async_add_lock_from_sensor,
gateway.evaluate_add_device(async_add_lock_from_sensor),
EventType.ADDED,
)
)
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/deconz/number.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ def async_add_sensor(_: EventType, sensor_id: str) -> None:

config_entry.async_on_unload(
gateway.api.sensors.presence.subscribe(
async_add_sensor,
gateway.evaluate_add_device(async_add_sensor),
EventType.ADDED,
)
)
Expand Down
1 change: 1 addition & 0 deletions homeassistant/components/deconz/services.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@ async def async_refresh_devices_service(gateway: DeconzGateway) -> None:
"""Refresh available devices from deCONZ."""
gateway.ignore_state_updates = True
await gateway.api.refresh_state()
gateway.load_ignored_devices()
gateway.ignore_state_updates = False

for resource_type in gateway.deconz_resource_type_to_signal_new_device:
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/deconz/siren.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ def async_add_siren(_: EventType, siren_id: str) -> None:

config_entry.async_on_unload(
gateway.api.lights.sirens.subscribe(
async_add_siren,
gateway.evaluate_add_device(async_add_siren),
EventType.ADDED,
)
)
Expand Down
14 changes: 7 additions & 7 deletions homeassistant/components/deconz/switch.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,21 +30,21 @@ async def async_setup_entry(
gateway.entities[DOMAIN] = set()

@callback
def async_add_switch(_: EventType, light_id: str) -> None:
def async_add_switch(_: EventType, switch_id: str) -> None:
"""Add switch from deCONZ."""
light = gateway.api.lights.lights[light_id]
if light.type not in POWER_PLUGS:
switch = gateway.api.lights.lights[switch_id]
if switch.type not in POWER_PLUGS:
return
async_add_entities([DeconzPowerPlug(light, gateway)])
async_add_entities([DeconzPowerPlug(switch, gateway)])

config_entry.async_on_unload(
gateway.api.lights.lights.subscribe(
async_add_switch,
gateway.evaluate_add_device(async_add_switch),
EventType.ADDED,
)
)
for light_id in gateway.api.lights.lights:
async_add_switch(EventType.ADDED, light_id)
for switch_id in gateway.api.lights.lights:
async_add_switch(EventType.ADDED, switch_id)


class DeconzPowerPlug(DeconzDevice, SwitchEntity):
Expand Down