deCONZ add new device without restart (#14221)
* Add new device without restarting hass * Remove debug prints * Fix copy paste error * Fix comments from balloob Add tests to verify signalling with new added devices * Fix hound comments Add test to verify when new sensor is added * Fix tests * Unload entry should unsubscribe all deconz dispatchers * Make sure mock setup also creates unsub in hass data * Fix copy paste issue * Lint
This commit is contained in:
parent
af8cd63838
commit
8410b63d9c
11 changed files with 212 additions and 48 deletions
|
@ -6,9 +6,10 @@ https://home-assistant.io/components/binary_sensor.deconz/
|
||||||
"""
|
"""
|
||||||
from homeassistant.components.binary_sensor import BinarySensorDevice
|
from homeassistant.components.binary_sensor import BinarySensorDevice
|
||||||
from homeassistant.components.deconz import (
|
from homeassistant.components.deconz import (
|
||||||
DOMAIN as DATA_DECONZ, DATA_DECONZ_ID)
|
DOMAIN as DATA_DECONZ, DATA_DECONZ_ID, DATA_DECONZ_UNSUB)
|
||||||
from homeassistant.const import ATTR_BATTERY_LEVEL
|
from homeassistant.const import ATTR_BATTERY_LEVEL
|
||||||
from homeassistant.core import callback
|
from homeassistant.core import callback
|
||||||
|
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
||||||
|
|
||||||
DEPENDENCIES = ['deconz']
|
DEPENDENCIES = ['deconz']
|
||||||
|
|
||||||
|
@ -21,14 +22,19 @@ async def async_setup_platform(hass, config, async_add_devices,
|
||||||
|
|
||||||
async def async_setup_entry(hass, config_entry, async_add_devices):
|
async def async_setup_entry(hass, config_entry, async_add_devices):
|
||||||
"""Set up the deCONZ binary sensor."""
|
"""Set up the deCONZ binary sensor."""
|
||||||
from pydeconz.sensor import DECONZ_BINARY_SENSOR
|
@callback
|
||||||
sensors = hass.data[DATA_DECONZ].sensors
|
def async_add_sensor(sensors):
|
||||||
entities = []
|
"""Add binary sensor from deCONZ."""
|
||||||
|
from pydeconz.sensor import DECONZ_BINARY_SENSOR
|
||||||
|
entities = []
|
||||||
|
for sensor in sensors:
|
||||||
|
if sensor.type in DECONZ_BINARY_SENSOR:
|
||||||
|
entities.append(DeconzBinarySensor(sensor))
|
||||||
|
async_add_devices(entities, True)
|
||||||
|
hass.data[DATA_DECONZ_UNSUB].append(
|
||||||
|
async_dispatcher_connect(hass, 'deconz_new_sensor', async_add_sensor))
|
||||||
|
|
||||||
for sensor in sensors.values():
|
async_add_sensor(hass.data[DATA_DECONZ].sensors.values())
|
||||||
if sensor and sensor.type in DECONZ_BINARY_SENSOR:
|
|
||||||
entities.append(DeconzBinarySensor(sensor))
|
|
||||||
async_add_devices(entities, True)
|
|
||||||
|
|
||||||
|
|
||||||
class DeconzBinarySensor(BinarySensorDevice):
|
class DeconzBinarySensor(BinarySensorDevice):
|
||||||
|
|
|
@ -11,15 +11,18 @@ from homeassistant.const import (
|
||||||
CONF_ID, CONF_PORT, EVENT_HOMEASSISTANT_STOP)
|
CONF_ID, CONF_PORT, EVENT_HOMEASSISTANT_STOP)
|
||||||
from homeassistant.core import EventOrigin, callback
|
from homeassistant.core import EventOrigin, callback
|
||||||
from homeassistant.helpers import aiohttp_client, config_validation as cv
|
from homeassistant.helpers import aiohttp_client, config_validation as cv
|
||||||
|
from homeassistant.helpers.dispatcher import (
|
||||||
|
async_dispatcher_connect, async_dispatcher_send)
|
||||||
from homeassistant.util import slugify
|
from homeassistant.util import slugify
|
||||||
from homeassistant.util.json import load_json
|
from homeassistant.util.json import load_json
|
||||||
|
|
||||||
# Loading the config flow file will register the flow
|
# Loading the config flow file will register the flow
|
||||||
from .config_flow import configured_hosts
|
from .config_flow import configured_hosts
|
||||||
from .const import (
|
from .const import (
|
||||||
CONFIG_FILE, DATA_DECONZ_EVENT, DATA_DECONZ_ID, DOMAIN, _LOGGER)
|
CONFIG_FILE, DATA_DECONZ_EVENT, DATA_DECONZ_ID,
|
||||||
|
DATA_DECONZ_UNSUB, DOMAIN, _LOGGER)
|
||||||
|
|
||||||
REQUIREMENTS = ['pydeconz==36']
|
REQUIREMENTS = ['pydeconz==37']
|
||||||
|
|
||||||
CONFIG_SCHEMA = vol.Schema({
|
CONFIG_SCHEMA = vol.Schema({
|
||||||
DOMAIN: vol.Schema({
|
DOMAIN: vol.Schema({
|
||||||
|
@ -69,14 +72,20 @@ async def async_setup_entry(hass, config_entry):
|
||||||
Start websocket for push notification of state changes from deCONZ.
|
Start websocket for push notification of state changes from deCONZ.
|
||||||
"""
|
"""
|
||||||
from pydeconz import DeconzSession
|
from pydeconz import DeconzSession
|
||||||
from pydeconz.sensor import SWITCH as DECONZ_REMOTE
|
|
||||||
if DOMAIN in hass.data:
|
if DOMAIN in hass.data:
|
||||||
_LOGGER.error(
|
_LOGGER.error(
|
||||||
"Config entry failed since one deCONZ instance already exists")
|
"Config entry failed since one deCONZ instance already exists")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
@callback
|
||||||
|
def async_add_device_callback(device_type, device):
|
||||||
|
"""Called when a new device has been created in deCONZ."""
|
||||||
|
async_dispatcher_send(
|
||||||
|
hass, 'deconz_new_{}'.format(device_type), [device])
|
||||||
|
|
||||||
session = aiohttp_client.async_get_clientsession(hass)
|
session = aiohttp_client.async_get_clientsession(hass)
|
||||||
deconz = DeconzSession(hass.loop, session, **config_entry.data)
|
deconz = DeconzSession(hass.loop, session, **config_entry.data,
|
||||||
|
async_add_device=async_add_device_callback)
|
||||||
result = await deconz.async_load_parameters()
|
result = await deconz.async_load_parameters()
|
||||||
if result is False:
|
if result is False:
|
||||||
_LOGGER.error("Failed to communicate with deCONZ")
|
_LOGGER.error("Failed to communicate with deCONZ")
|
||||||
|
@ -84,14 +93,24 @@ async def async_setup_entry(hass, config_entry):
|
||||||
|
|
||||||
hass.data[DOMAIN] = deconz
|
hass.data[DOMAIN] = deconz
|
||||||
hass.data[DATA_DECONZ_ID] = {}
|
hass.data[DATA_DECONZ_ID] = {}
|
||||||
|
hass.data[DATA_DECONZ_EVENT] = []
|
||||||
|
hass.data[DATA_DECONZ_UNSUB] = []
|
||||||
|
|
||||||
for component in ['binary_sensor', 'light', 'scene', 'sensor']:
|
for component in ['binary_sensor', 'light', 'scene', 'sensor']:
|
||||||
hass.async_add_job(hass.config_entries.async_forward_entry_setup(
|
hass.async_add_job(hass.config_entries.async_forward_entry_setup(
|
||||||
config_entry, component))
|
config_entry, component))
|
||||||
|
|
||||||
hass.data[DATA_DECONZ_EVENT] = [DeconzEvent(
|
@callback
|
||||||
hass, sensor) for sensor in deconz.sensors.values()
|
def async_add_remote(sensors):
|
||||||
if sensor.type in DECONZ_REMOTE]
|
"""Setup remote from deCONZ."""
|
||||||
|
from pydeconz.sensor import SWITCH as DECONZ_REMOTE
|
||||||
|
for sensor in sensors:
|
||||||
|
if sensor.type in DECONZ_REMOTE:
|
||||||
|
hass.data[DATA_DECONZ_EVENT].append(DeconzEvent(hass, sensor))
|
||||||
|
hass.data[DATA_DECONZ_UNSUB].append(
|
||||||
|
async_dispatcher_connect(hass, 'deconz_new_sensor', async_add_remote))
|
||||||
|
|
||||||
|
async_add_remote(deconz.sensors.values())
|
||||||
|
|
||||||
deconz.start()
|
deconz.start()
|
||||||
|
|
||||||
|
@ -148,6 +167,10 @@ async def async_unload_entry(hass, config_entry):
|
||||||
for component in ['binary_sensor', 'light', 'scene', 'sensor']:
|
for component in ['binary_sensor', 'light', 'scene', 'sensor']:
|
||||||
await hass.config_entries.async_forward_entry_unload(
|
await hass.config_entries.async_forward_entry_unload(
|
||||||
config_entry, component)
|
config_entry, component)
|
||||||
|
dispatchers = hass.data[DATA_DECONZ_UNSUB]
|
||||||
|
for unsub_dispatcher in dispatchers:
|
||||||
|
unsub_dispatcher()
|
||||||
|
hass.data[DATA_DECONZ_UNSUB] = []
|
||||||
hass.data[DATA_DECONZ_EVENT] = []
|
hass.data[DATA_DECONZ_EVENT] = []
|
||||||
hass.data[DATA_DECONZ_ID] = []
|
hass.data[DATA_DECONZ_ID] = []
|
||||||
return True
|
return True
|
||||||
|
|
|
@ -7,3 +7,4 @@ DOMAIN = 'deconz'
|
||||||
CONFIG_FILE = 'deconz.conf'
|
CONFIG_FILE = 'deconz.conf'
|
||||||
DATA_DECONZ_EVENT = 'deconz_events'
|
DATA_DECONZ_EVENT = 'deconz_events'
|
||||||
DATA_DECONZ_ID = 'deconz_entities'
|
DATA_DECONZ_ID = 'deconz_entities'
|
||||||
|
DATA_DECONZ_UNSUB = 'deconz_dispatchers'
|
||||||
|
|
|
@ -5,13 +5,14 @@ For more details about this component, please refer to the documentation at
|
||||||
https://home-assistant.io/components/light.deconz/
|
https://home-assistant.io/components/light.deconz/
|
||||||
"""
|
"""
|
||||||
from homeassistant.components.deconz import (
|
from homeassistant.components.deconz import (
|
||||||
DOMAIN as DATA_DECONZ, DATA_DECONZ_ID)
|
DOMAIN as DATA_DECONZ, DATA_DECONZ_ID, DATA_DECONZ_UNSUB)
|
||||||
from homeassistant.components.light import (
|
from homeassistant.components.light import (
|
||||||
ATTR_BRIGHTNESS, ATTR_COLOR_TEMP, ATTR_EFFECT, ATTR_FLASH, ATTR_HS_COLOR,
|
ATTR_BRIGHTNESS, ATTR_COLOR_TEMP, ATTR_EFFECT, ATTR_FLASH, ATTR_HS_COLOR,
|
||||||
ATTR_TRANSITION, EFFECT_COLORLOOP, FLASH_LONG, FLASH_SHORT,
|
ATTR_TRANSITION, EFFECT_COLORLOOP, FLASH_LONG, FLASH_SHORT,
|
||||||
SUPPORT_BRIGHTNESS, SUPPORT_COLOR, SUPPORT_COLOR_TEMP, SUPPORT_EFFECT,
|
SUPPORT_BRIGHTNESS, SUPPORT_COLOR, SUPPORT_COLOR_TEMP, SUPPORT_EFFECT,
|
||||||
SUPPORT_FLASH, SUPPORT_TRANSITION, Light)
|
SUPPORT_FLASH, SUPPORT_TRANSITION, Light)
|
||||||
from homeassistant.core import callback
|
from homeassistant.core import callback
|
||||||
|
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
||||||
import homeassistant.util.color as color_util
|
import homeassistant.util.color as color_util
|
||||||
|
|
||||||
DEPENDENCIES = ['deconz']
|
DEPENDENCIES = ['deconz']
|
||||||
|
@ -19,23 +20,35 @@ DEPENDENCIES = ['deconz']
|
||||||
|
|
||||||
async def async_setup_platform(hass, config, async_add_devices,
|
async def async_setup_platform(hass, config, async_add_devices,
|
||||||
discovery_info=None):
|
discovery_info=None):
|
||||||
"""Old way of setting up deCONZ lights."""
|
"""Old way of setting up deCONZ lights and group."""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
async def async_setup_entry(hass, config_entry, async_add_devices):
|
async def async_setup_entry(hass, config_entry, async_add_devices):
|
||||||
"""Set up the deCONZ lights from a config entry."""
|
"""Set up the deCONZ lights and groups from a config entry."""
|
||||||
lights = hass.data[DATA_DECONZ].lights
|
@callback
|
||||||
groups = hass.data[DATA_DECONZ].groups
|
def async_add_light(lights):
|
||||||
entities = []
|
"""Add light from deCONZ."""
|
||||||
|
entities = []
|
||||||
|
for light in lights:
|
||||||
|
entities.append(DeconzLight(light))
|
||||||
|
async_add_devices(entities, True)
|
||||||
|
hass.data[DATA_DECONZ_UNSUB].append(
|
||||||
|
async_dispatcher_connect(hass, 'deconz_new_light', async_add_light))
|
||||||
|
|
||||||
for light in lights.values():
|
@callback
|
||||||
entities.append(DeconzLight(light))
|
def async_add_group(groups):
|
||||||
|
"""Add group from deCONZ."""
|
||||||
|
entities = []
|
||||||
|
for group in groups:
|
||||||
|
if group.lights:
|
||||||
|
entities.append(DeconzLight(group))
|
||||||
|
async_add_devices(entities, True)
|
||||||
|
hass.data[DATA_DECONZ_UNSUB].append(
|
||||||
|
async_dispatcher_connect(hass, 'deconz_new_group', async_add_group))
|
||||||
|
|
||||||
for group in groups.values():
|
async_add_light(hass.data[DATA_DECONZ].lights.values())
|
||||||
if group.lights: # Don't create entity for group not containing light
|
async_add_group(hass.data[DATA_DECONZ].groups.values())
|
||||||
entities.append(DeconzLight(group))
|
|
||||||
async_add_devices(entities, True)
|
|
||||||
|
|
||||||
|
|
||||||
class DeconzLight(Light):
|
class DeconzLight(Light):
|
||||||
|
|
|
@ -5,10 +5,11 @@ For more details about this component, please refer to the documentation at
|
||||||
https://home-assistant.io/components/sensor.deconz/
|
https://home-assistant.io/components/sensor.deconz/
|
||||||
"""
|
"""
|
||||||
from homeassistant.components.deconz import (
|
from homeassistant.components.deconz import (
|
||||||
DOMAIN as DATA_DECONZ, DATA_DECONZ_ID)
|
DOMAIN as DATA_DECONZ, DATA_DECONZ_ID, DATA_DECONZ_UNSUB)
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
ATTR_BATTERY_LEVEL, ATTR_VOLTAGE, DEVICE_CLASS_BATTERY)
|
ATTR_BATTERY_LEVEL, ATTR_VOLTAGE, DEVICE_CLASS_BATTERY)
|
||||||
from homeassistant.core import callback
|
from homeassistant.core import callback
|
||||||
|
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
||||||
from homeassistant.helpers.entity import Entity
|
from homeassistant.helpers.entity import Entity
|
||||||
from homeassistant.util import slugify
|
from homeassistant.util import slugify
|
||||||
|
|
||||||
|
@ -27,18 +28,23 @@ async def async_setup_platform(hass, config, async_add_devices,
|
||||||
|
|
||||||
async def async_setup_entry(hass, config_entry, async_add_devices):
|
async def async_setup_entry(hass, config_entry, async_add_devices):
|
||||||
"""Set up the deCONZ sensors."""
|
"""Set up the deCONZ sensors."""
|
||||||
from pydeconz.sensor import DECONZ_SENSOR, SWITCH as DECONZ_REMOTE
|
@callback
|
||||||
sensors = hass.data[DATA_DECONZ].sensors
|
def async_add_sensor(sensors):
|
||||||
entities = []
|
"""Add sensors from deCONZ."""
|
||||||
|
from pydeconz.sensor import DECONZ_SENSOR, SWITCH as DECONZ_REMOTE
|
||||||
|
entities = []
|
||||||
|
for sensor in sensors:
|
||||||
|
if sensor.type in DECONZ_SENSOR:
|
||||||
|
if sensor.type in DECONZ_REMOTE:
|
||||||
|
if sensor.battery:
|
||||||
|
entities.append(DeconzBattery(sensor))
|
||||||
|
else:
|
||||||
|
entities.append(DeconzSensor(sensor))
|
||||||
|
async_add_devices(entities, True)
|
||||||
|
hass.data[DATA_DECONZ_UNSUB].append(
|
||||||
|
async_dispatcher_connect(hass, 'deconz_new_sensor', async_add_sensor))
|
||||||
|
|
||||||
for sensor in sensors.values():
|
async_add_sensor(hass.data[DATA_DECONZ].sensors.values())
|
||||||
if sensor and sensor.type in DECONZ_SENSOR:
|
|
||||||
if sensor.type in DECONZ_REMOTE:
|
|
||||||
if sensor.battery:
|
|
||||||
entities.append(DeconzBattery(sensor))
|
|
||||||
else:
|
|
||||||
entities.append(DeconzSensor(sensor))
|
|
||||||
async_add_devices(entities, True)
|
|
||||||
|
|
||||||
|
|
||||||
class DeconzSensor(Entity):
|
class DeconzSensor(Entity):
|
||||||
|
|
|
@ -745,7 +745,7 @@ pycsspeechtts==1.0.2
|
||||||
pydaikin==0.4
|
pydaikin==0.4
|
||||||
|
|
||||||
# homeassistant.components.deconz
|
# homeassistant.components.deconz
|
||||||
pydeconz==36
|
pydeconz==37
|
||||||
|
|
||||||
# homeassistant.components.zwave
|
# homeassistant.components.zwave
|
||||||
pydispatcher==2.0.5
|
pydispatcher==2.0.5
|
||||||
|
|
|
@ -133,7 +133,7 @@ py-canary==0.5.0
|
||||||
pyblackbird==0.5
|
pyblackbird==0.5
|
||||||
|
|
||||||
# homeassistant.components.deconz
|
# homeassistant.components.deconz
|
||||||
pydeconz==36
|
pydeconz==37
|
||||||
|
|
||||||
# homeassistant.components.zwave
|
# homeassistant.components.zwave
|
||||||
pydispatcher==2.0.5
|
pydispatcher==2.0.5
|
||||||
|
|
|
@ -3,6 +3,7 @@ from unittest.mock import Mock, patch
|
||||||
|
|
||||||
from homeassistant import config_entries
|
from homeassistant import config_entries
|
||||||
from homeassistant.components import deconz
|
from homeassistant.components import deconz
|
||||||
|
from homeassistant.helpers.dispatcher import async_dispatcher_send
|
||||||
|
|
||||||
from tests.common import mock_coro
|
from tests.common import mock_coro
|
||||||
|
|
||||||
|
@ -14,6 +15,13 @@ SENSOR = {
|
||||||
"type": "ZHAPresence",
|
"type": "ZHAPresence",
|
||||||
"state": {"presence": False},
|
"state": {"presence": False},
|
||||||
"config": {}
|
"config": {}
|
||||||
|
},
|
||||||
|
"2": {
|
||||||
|
"id": "Sensor 2 id",
|
||||||
|
"name": "Sensor 2 name",
|
||||||
|
"type": "ZHATemperature",
|
||||||
|
"state": {"temperature": False},
|
||||||
|
"config": {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,6 +38,7 @@ async def setup_bridge(hass, data):
|
||||||
return_value=mock_coro(data)):
|
return_value=mock_coro(data)):
|
||||||
await bridge.async_load_parameters()
|
await bridge.async_load_parameters()
|
||||||
hass.data[deconz.DOMAIN] = bridge
|
hass.data[deconz.DOMAIN] = bridge
|
||||||
|
hass.data[deconz.DATA_DECONZ_UNSUB] = []
|
||||||
hass.data[deconz.DATA_DECONZ_ID] = {}
|
hass.data[deconz.DATA_DECONZ_ID] = {}
|
||||||
config_entry = config_entries.ConfigEntry(
|
config_entry = config_entries.ConfigEntry(
|
||||||
1, deconz.DOMAIN, 'Mock Title', {'host': 'mock-host'}, 'test')
|
1, deconz.DOMAIN, 'Mock Title', {'host': 'mock-host'}, 'test')
|
||||||
|
@ -40,7 +49,7 @@ async def setup_bridge(hass, data):
|
||||||
|
|
||||||
|
|
||||||
async def test_no_binary_sensors(hass):
|
async def test_no_binary_sensors(hass):
|
||||||
"""Test the update_lights function with some lights."""
|
"""Test that no sensors in deconz results in no sensor entities."""
|
||||||
data = {}
|
data = {}
|
||||||
await setup_bridge(hass, data)
|
await setup_bridge(hass, data)
|
||||||
assert len(hass.data[deconz.DATA_DECONZ_ID]) == 0
|
assert len(hass.data[deconz.DATA_DECONZ_ID]) == 0
|
||||||
|
@ -48,8 +57,23 @@ async def test_no_binary_sensors(hass):
|
||||||
|
|
||||||
|
|
||||||
async def test_binary_sensors(hass):
|
async def test_binary_sensors(hass):
|
||||||
"""Test the update_lights function with some lights."""
|
"""Test successful creation of binary sensor entities."""
|
||||||
data = {"sensors": SENSOR}
|
data = {"sensors": SENSOR}
|
||||||
await setup_bridge(hass, data)
|
await setup_bridge(hass, data)
|
||||||
assert "binary_sensor.sensor_1_name" in hass.data[deconz.DATA_DECONZ_ID]
|
assert "binary_sensor.sensor_1_name" in hass.data[deconz.DATA_DECONZ_ID]
|
||||||
|
assert "binary_sensor.sensor_2_name" not in \
|
||||||
|
hass.data[deconz.DATA_DECONZ_ID]
|
||||||
assert len(hass.states.async_all()) == 1
|
assert len(hass.states.async_all()) == 1
|
||||||
|
|
||||||
|
|
||||||
|
async def test_add_new_sensor(hass):
|
||||||
|
"""Test successful creation of sensor entities."""
|
||||||
|
data = {}
|
||||||
|
await setup_bridge(hass, data)
|
||||||
|
sensor = Mock()
|
||||||
|
sensor.name = 'name'
|
||||||
|
sensor.type = 'ZHAPresence'
|
||||||
|
sensor.register_async_callback = Mock()
|
||||||
|
async_dispatcher_send(hass, 'deconz_new_sensor', [sensor])
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
assert "binary_sensor.name" in hass.data[deconz.DATA_DECONZ_ID]
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
"""Test deCONZ component setup process."""
|
"""Test deCONZ component setup process."""
|
||||||
from unittest.mock import Mock, patch
|
from unittest.mock import Mock, patch
|
||||||
|
|
||||||
|
from homeassistant.helpers.dispatcher import async_dispatcher_send
|
||||||
from homeassistant.setup import async_setup_component
|
from homeassistant.setup import async_setup_component
|
||||||
from homeassistant.components import deconz
|
from homeassistant.components import deconz
|
||||||
|
|
||||||
|
@ -97,6 +98,7 @@ async def test_setup_entry_successful(hass):
|
||||||
assert await deconz.async_setup_entry(hass, entry) is True
|
assert await deconz.async_setup_entry(hass, entry) is True
|
||||||
assert hass.data[deconz.DOMAIN]
|
assert hass.data[deconz.DOMAIN]
|
||||||
assert hass.data[deconz.DATA_DECONZ_ID] == {}
|
assert hass.data[deconz.DATA_DECONZ_ID] == {}
|
||||||
|
assert len(hass.data[deconz.DATA_DECONZ_UNSUB]) == 1
|
||||||
assert len(mock_add_job.mock_calls) == 4
|
assert len(mock_add_job.mock_calls) == 4
|
||||||
assert len(mock_config_entries.async_forward_entry_setup.mock_calls) == 4
|
assert len(mock_config_entries.async_forward_entry_setup.mock_calls) == 4
|
||||||
assert mock_config_entries.async_forward_entry_setup.mock_calls[0][1] == \
|
assert mock_config_entries.async_forward_entry_setup.mock_calls[0][1] == \
|
||||||
|
@ -121,5 +123,52 @@ async def test_unload_entry(hass):
|
||||||
hass.data[deconz.DATA_DECONZ_ID] = {'id': 'deconzid'}
|
hass.data[deconz.DATA_DECONZ_ID] = {'id': 'deconzid'}
|
||||||
assert await deconz.async_unload_entry(hass, entry)
|
assert await deconz.async_unload_entry(hass, entry)
|
||||||
assert deconz.DOMAIN not in hass.data
|
assert deconz.DOMAIN not in hass.data
|
||||||
|
assert len(hass.data[deconz.DATA_DECONZ_UNSUB]) == 0
|
||||||
assert len(hass.data[deconz.DATA_DECONZ_EVENT]) == 0
|
assert len(hass.data[deconz.DATA_DECONZ_EVENT]) == 0
|
||||||
assert len(hass.data[deconz.DATA_DECONZ_ID]) == 0
|
assert len(hass.data[deconz.DATA_DECONZ_ID]) == 0
|
||||||
|
|
||||||
|
|
||||||
|
async def test_add_new_device(hass):
|
||||||
|
"""Test adding a new device generates a signal for platforms."""
|
||||||
|
new_event = {
|
||||||
|
"t": "event",
|
||||||
|
"e": "added",
|
||||||
|
"r": "sensors",
|
||||||
|
"id": "1",
|
||||||
|
"sensor": {
|
||||||
|
"config": {
|
||||||
|
"on": "True",
|
||||||
|
"reachable": "True"
|
||||||
|
},
|
||||||
|
"name": "event",
|
||||||
|
"state": {},
|
||||||
|
"type": "ZHASwitch"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
entry = Mock()
|
||||||
|
entry.data = {'host': '1.2.3.4', 'port': 80, 'api_key': '1234567890ABCDEF'}
|
||||||
|
with patch.object(deconz, 'async_dispatcher_send') as mock_dispatch_send, \
|
||||||
|
patch('pydeconz.DeconzSession.async_load_parameters',
|
||||||
|
return_value=mock_coro(True)):
|
||||||
|
assert await deconz.async_setup_entry(hass, entry) is True
|
||||||
|
hass.data[deconz.DOMAIN].async_event_handler(new_event)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
assert len(mock_dispatch_send.mock_calls) == 1
|
||||||
|
assert len(mock_dispatch_send.mock_calls[0]) == 3
|
||||||
|
|
||||||
|
|
||||||
|
async def test_add_new_remote(hass):
|
||||||
|
"""Test new added device creates a new remote."""
|
||||||
|
entry = Mock()
|
||||||
|
entry.data = {'host': '1.2.3.4', 'port': 80, 'api_key': '1234567890ABCDEF'}
|
||||||
|
remote = Mock()
|
||||||
|
remote.name = 'name'
|
||||||
|
remote.type = 'ZHASwitch'
|
||||||
|
remote.register_async_callback = Mock()
|
||||||
|
with patch('pydeconz.DeconzSession.async_load_parameters',
|
||||||
|
return_value=mock_coro(True)):
|
||||||
|
assert await deconz.async_setup_entry(hass, entry) is True
|
||||||
|
|
||||||
|
async_dispatcher_send(hass, 'deconz_new_sensor', [remote])
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
assert len(hass.data[deconz.DATA_DECONZ_EVENT]) == 1
|
||||||
|
|
|
@ -3,6 +3,7 @@ from unittest.mock import Mock, patch
|
||||||
|
|
||||||
from homeassistant import config_entries
|
from homeassistant import config_entries
|
||||||
from homeassistant.components import deconz
|
from homeassistant.components import deconz
|
||||||
|
from homeassistant.helpers.dispatcher import async_dispatcher_send
|
||||||
|
|
||||||
from tests.common import mock_coro
|
from tests.common import mock_coro
|
||||||
|
|
||||||
|
@ -49,6 +50,7 @@ async def setup_bridge(hass, data):
|
||||||
return_value=mock_coro(data)):
|
return_value=mock_coro(data)):
|
||||||
await bridge.async_load_parameters()
|
await bridge.async_load_parameters()
|
||||||
hass.data[deconz.DOMAIN] = bridge
|
hass.data[deconz.DOMAIN] = bridge
|
||||||
|
hass.data[deconz.DATA_DECONZ_UNSUB] = []
|
||||||
hass.data[deconz.DATA_DECONZ_ID] = {}
|
hass.data[deconz.DATA_DECONZ_ID] = {}
|
||||||
config_entry = config_entries.ConfigEntry(
|
config_entry = config_entries.ConfigEntry(
|
||||||
1, deconz.DOMAIN, 'Mock Title', {'host': 'mock-host'}, 'test')
|
1, deconz.DOMAIN, 'Mock Title', {'host': 'mock-host'}, 'test')
|
||||||
|
@ -58,7 +60,7 @@ async def setup_bridge(hass, data):
|
||||||
|
|
||||||
|
|
||||||
async def test_no_lights_or_groups(hass):
|
async def test_no_lights_or_groups(hass):
|
||||||
"""Test the update_lights function with some lights."""
|
"""Test that no lights or groups entities are created."""
|
||||||
data = {}
|
data = {}
|
||||||
await setup_bridge(hass, data)
|
await setup_bridge(hass, data)
|
||||||
assert len(hass.data[deconz.DATA_DECONZ_ID]) == 0
|
assert len(hass.data[deconz.DATA_DECONZ_ID]) == 0
|
||||||
|
@ -66,9 +68,33 @@ async def test_no_lights_or_groups(hass):
|
||||||
|
|
||||||
|
|
||||||
async def test_lights_and_groups(hass):
|
async def test_lights_and_groups(hass):
|
||||||
"""Test the update_lights function with some lights."""
|
"""Test that lights or groups entities are created."""
|
||||||
await setup_bridge(hass, {"lights": LIGHT, "groups": GROUP})
|
await setup_bridge(hass, {"lights": LIGHT, "groups": GROUP})
|
||||||
assert "light.light_1_name" in hass.data[deconz.DATA_DECONZ_ID]
|
assert "light.light_1_name" in hass.data[deconz.DATA_DECONZ_ID]
|
||||||
assert "light.group_1_name" in hass.data[deconz.DATA_DECONZ_ID]
|
assert "light.group_1_name" in hass.data[deconz.DATA_DECONZ_ID]
|
||||||
assert "light.group_2_name" not in hass.data[deconz.DATA_DECONZ_ID]
|
assert "light.group_2_name" not in hass.data[deconz.DATA_DECONZ_ID]
|
||||||
assert len(hass.states.async_all()) == 3
|
assert len(hass.states.async_all()) == 3
|
||||||
|
|
||||||
|
|
||||||
|
async def test_add_new_light(hass):
|
||||||
|
"""Test successful creation of light entities."""
|
||||||
|
data = {}
|
||||||
|
await setup_bridge(hass, data)
|
||||||
|
light = Mock()
|
||||||
|
light.name = 'name'
|
||||||
|
light.register_async_callback = Mock()
|
||||||
|
async_dispatcher_send(hass, 'deconz_new_light', [light])
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
assert "light.name" in hass.data[deconz.DATA_DECONZ_ID]
|
||||||
|
|
||||||
|
|
||||||
|
async def test_add_new_group(hass):
|
||||||
|
"""Test successful creation of group entities."""
|
||||||
|
data = {}
|
||||||
|
await setup_bridge(hass, data)
|
||||||
|
group = Mock()
|
||||||
|
group.name = 'name'
|
||||||
|
group.register_async_callback = Mock()
|
||||||
|
async_dispatcher_send(hass, 'deconz_new_group', [group])
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
assert "light.name" in hass.data[deconz.DATA_DECONZ_ID]
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
"""deCONZ sensor platform tests."""
|
"""deCONZ sensor platform tests."""
|
||||||
from unittest.mock import Mock, patch
|
from unittest.mock import Mock, patch
|
||||||
|
|
||||||
|
|
||||||
from homeassistant import config_entries
|
from homeassistant import config_entries
|
||||||
from homeassistant.components import deconz
|
from homeassistant.components import deconz
|
||||||
|
from homeassistant.helpers.dispatcher import async_dispatcher_send
|
||||||
|
|
||||||
from tests.common import mock_coro
|
from tests.common import mock_coro
|
||||||
|
|
||||||
|
@ -51,6 +53,7 @@ async def setup_bridge(hass, data):
|
||||||
return_value=mock_coro(data)):
|
return_value=mock_coro(data)):
|
||||||
await bridge.async_load_parameters()
|
await bridge.async_load_parameters()
|
||||||
hass.data[deconz.DOMAIN] = bridge
|
hass.data[deconz.DOMAIN] = bridge
|
||||||
|
hass.data[deconz.DATA_DECONZ_UNSUB] = []
|
||||||
hass.data[deconz.DATA_DECONZ_EVENT] = []
|
hass.data[deconz.DATA_DECONZ_EVENT] = []
|
||||||
hass.data[deconz.DATA_DECONZ_ID] = {}
|
hass.data[deconz.DATA_DECONZ_ID] = {}
|
||||||
config_entry = config_entries.ConfigEntry(
|
config_entry = config_entries.ConfigEntry(
|
||||||
|
@ -61,15 +64,15 @@ async def setup_bridge(hass, data):
|
||||||
|
|
||||||
|
|
||||||
async def test_no_sensors(hass):
|
async def test_no_sensors(hass):
|
||||||
"""Test the update_lights function with some lights."""
|
"""Test that no sensors in deconz results in no sensor entities."""
|
||||||
data = {}
|
data = {}
|
||||||
await setup_bridge(hass, data)
|
await setup_bridge(hass, data)
|
||||||
assert len(hass.data[deconz.DATA_DECONZ_ID]) == 0
|
assert len(hass.data[deconz.DATA_DECONZ_ID]) == 0
|
||||||
assert len(hass.states.async_all()) == 0
|
assert len(hass.states.async_all()) == 0
|
||||||
|
|
||||||
|
|
||||||
async def test_binary_sensors(hass):
|
async def test_sensors(hass):
|
||||||
"""Test the update_lights function with some lights."""
|
"""Test successful creation of sensor entities."""
|
||||||
data = {"sensors": SENSOR}
|
data = {"sensors": SENSOR}
|
||||||
await setup_bridge(hass, data)
|
await setup_bridge(hass, data)
|
||||||
assert "sensor.sensor_1_name" in hass.data[deconz.DATA_DECONZ_ID]
|
assert "sensor.sensor_1_name" in hass.data[deconz.DATA_DECONZ_ID]
|
||||||
|
@ -81,3 +84,16 @@ async def test_binary_sensors(hass):
|
||||||
assert "sensor.sensor_4_name_battery_level" in \
|
assert "sensor.sensor_4_name_battery_level" in \
|
||||||
hass.data[deconz.DATA_DECONZ_ID]
|
hass.data[deconz.DATA_DECONZ_ID]
|
||||||
assert len(hass.states.async_all()) == 2
|
assert len(hass.states.async_all()) == 2
|
||||||
|
|
||||||
|
|
||||||
|
async def test_add_new_sensor(hass):
|
||||||
|
"""Test successful creation of sensor entities."""
|
||||||
|
data = {}
|
||||||
|
await setup_bridge(hass, data)
|
||||||
|
sensor = Mock()
|
||||||
|
sensor.name = 'name'
|
||||||
|
sensor.type = 'ZHATemperature'
|
||||||
|
sensor.register_async_callback = Mock()
|
||||||
|
async_dispatcher_send(hass, 'deconz_new_sensor', [sensor])
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
assert "sensor.name" in hass.data[deconz.DATA_DECONZ_ID]
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue