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:
Robert Svensson 2018-05-05 16:11:00 +02:00 committed by Paulus Schoutsen
parent af8cd63838
commit 8410b63d9c
11 changed files with 212 additions and 48 deletions

View file

@ -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):

View file

@ -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

View file

@ -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'

View file

@ -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):

View file

@ -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):

View file

@ -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

View file

@ -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

View file

@ -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]

View file

@ -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

View file

@ -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]

View file

@ -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]