From 31b2f331db07da6dea533af8edfa91fd7d858ee4 Mon Sep 17 00:00:00 2001 From: Robert Svensson Date: Mon, 27 May 2019 06:56:00 +0200 Subject: [PATCH] Library refactorization of deCONZ (#23725) * Improved sensors * Lib update signalling * Replace reason with changed * Move imports to top of file * Add support for secondary temperature reported by some Xiaomi devices * Bump dependency to v59 --- homeassistant/components/deconz/__init__.py | 1 + .../components/deconz/binary_sensor.py | 41 +++++++------- homeassistant/components/deconz/climate.py | 13 +++-- .../components/deconz/config_flow.py | 10 ++-- homeassistant/components/deconz/cover.py | 2 +- .../components/deconz/deconz_device.py | 2 +- homeassistant/components/deconz/gateway.py | 15 +++--- homeassistant/components/deconz/light.py | 2 +- homeassistant/components/deconz/manifest.json | 2 +- homeassistant/components/deconz/scene.py | 2 +- homeassistant/components/deconz/sensor.py | 53 ++++++++++--------- homeassistant/components/deconz/switch.py | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- tests/components/deconz/test_binary_sensor.py | 5 +- tests/components/deconz/test_climate.py | 13 +++-- tests/components/deconz/test_config_flow.py | 12 +++-- tests/components/deconz/test_gateway.py | 3 +- tests/components/deconz/test_sensor.py | 5 +- 19 files changed, 104 insertions(+), 83 deletions(-) diff --git a/homeassistant/components/deconz/__init__.py b/homeassistant/components/deconz/__init__.py index 153e654f3fb..71e03da70b7 100644 --- a/homeassistant/components/deconz/__init__.py +++ b/homeassistant/components/deconz/__init__.py @@ -164,6 +164,7 @@ async def async_unload_entry(hass, config_entry): if not hass.data[DOMAIN]: hass.services.async_remove(DOMAIN, SERVICE_DECONZ) hass.services.async_remove(DOMAIN, SERVICE_DEVICE_REFRESH) + elif gateway.master: await async_populate_options(hass, config_entry) new_master_gateway = next(iter(hass.data[DOMAIN].values())) diff --git a/homeassistant/components/deconz/binary_sensor.py b/homeassistant/components/deconz/binary_sensor.py index fbb15abc744..6fe8b4324b3 100644 --- a/homeassistant/components/deconz/binary_sensor.py +++ b/homeassistant/components/deconz/binary_sensor.py @@ -1,6 +1,8 @@ """Support for deCONZ binary sensors.""" +from pydeconz.sensor import Presence, Vibration + from homeassistant.components.binary_sensor import BinarySensorDevice -from homeassistant.const import ATTR_BATTERY_LEVEL +from homeassistant.const import ATTR_BATTERY_LEVEL, ATTR_TEMPERATURE from homeassistant.core import callback from homeassistant.helpers.dispatcher import async_dispatcher_connect @@ -15,7 +17,7 @@ ATTR_VIBRATIONSTRENGTH = 'vibrationstrength' async def async_setup_platform( hass, config, async_add_entities, discovery_info=None): - """Old way of setting up deCONZ binary sensors.""" + """Old way of setting up deCONZ platforms.""" pass @@ -26,12 +28,11 @@ async def async_setup_entry(hass, config_entry, async_add_entities): @callback def async_add_sensor(sensors): """Add binary sensor from deCONZ.""" - from pydeconz.sensor import DECONZ_BINARY_SENSOR entities = [] for sensor in sensors: - if sensor.type in DECONZ_BINARY_SENSOR and \ + if sensor.BINARY and \ not (not gateway.allow_clip_sensor and sensor.type.startswith('CLIP')): @@ -49,16 +50,11 @@ class DeconzBinarySensor(DeconzDevice, BinarySensorDevice): """Representation of a deCONZ binary sensor.""" @callback - def async_update_callback(self, reason): - """Update the sensor's state. - - If reason is that state is updated, - or reachable has changed or battery has changed. - """ - if reason['state'] or \ - 'reachable' in reason['attr'] or \ - 'battery' in reason['attr'] or \ - 'on' in reason['attr']: + def async_update_callback(self, force_update=False): + """Update the sensor's state.""" + changed = set(self._device.changed_keys) + keys = {'battery', 'on', 'reachable', 'state'} + if force_update or any(key in changed for key in keys): self.async_schedule_update_ha_state() @property @@ -69,26 +65,33 @@ class DeconzBinarySensor(DeconzDevice, BinarySensorDevice): @property def device_class(self): """Return the class of the sensor.""" - return self._device.sensor_class + return self._device.SENSOR_CLASS @property def icon(self): """Return the icon to use in the frontend.""" - return self._device.sensor_icon + return self._device.SENSOR_ICON @property def device_state_attributes(self): """Return the state attributes of the sensor.""" - from pydeconz.sensor import PRESENCE, VIBRATION attr = {} if self._device.battery: attr[ATTR_BATTERY_LEVEL] = self._device.battery + if self._device.on is not None: attr[ATTR_ON] = self._device.on - if self._device.type in PRESENCE and self._device.dark is not None: + + if self._device.secondary_temperature is not None: + attr[ATTR_TEMPERATURE] = self._device.secondary_temperature + + if self._device.type in Presence.ZHATYPE and \ + self._device.dark is not None: attr[ATTR_DARK] = self._device.dark - elif self._device.type in VIBRATION: + + elif self._device.type in Vibration.ZHATYPE: attr[ATTR_ORIENTATION] = self._device.orientation attr[ATTR_TILTANGLE] = self._device.tiltangle attr[ATTR_VIBRATIONSTRENGTH] = self._device.vibrationstrength + return attr diff --git a/homeassistant/components/deconz/climate.py b/homeassistant/components/deconz/climate.py index c4a021a80c2..cde123f7f08 100644 --- a/homeassistant/components/deconz/climate.py +++ b/homeassistant/components/deconz/climate.py @@ -1,4 +1,6 @@ """Support for deCONZ climate devices.""" +from pydeconz.sensor import Thermostat + from homeassistant.components.climate import ClimateDevice from homeassistant.components.climate.const import ( SUPPORT_ON_OFF, SUPPORT_TARGET_TEMPERATURE) @@ -12,6 +14,12 @@ from .deconz_device import DeconzDevice from .gateway import get_gateway_from_config_entry +async def async_setup_platform( + hass, config, async_add_entities, discovery_info=None): + """Old way of setting up deCONZ platforms.""" + pass + + async def async_setup_entry(hass, config_entry, async_add_entities): """Set up the deCONZ climate devices. @@ -22,12 +30,11 @@ async def async_setup_entry(hass, config_entry, async_add_entities): @callback def async_add_climate(sensors): """Add climate devices from deCONZ.""" - from pydeconz.sensor import THERMOSTAT entities = [] for sensor in sensors: - if sensor.type in THERMOSTAT and \ + if sensor.type in Thermostat.ZHATYPE and \ not (not gateway.allow_clip_sensor and sensor.type.startswith('CLIP')): @@ -59,7 +66,7 @@ class DeconzThermostat(DeconzDevice, ClimateDevice): @property def is_on(self): """Return true if on.""" - return self._device.on + return self._device.state_on async def async_turn_on(self): """Turn on switch.""" diff --git a/homeassistant/components/deconz/config_flow.py b/homeassistant/components/deconz/config_flow.py index d9065ad2727..24eb3dd4d5d 100644 --- a/homeassistant/components/deconz/config_flow.py +++ b/homeassistant/components/deconz/config_flow.py @@ -4,6 +4,10 @@ import asyncio import async_timeout import voluptuous as vol +from pydeconz.errors import ResponseError, RequestError +from pydeconz.utils import ( + async_discovery, async_get_api_key, async_get_bridgeid) + from homeassistant import config_entries from homeassistant.const import CONF_API_KEY, CONF_HOST, CONF_PORT from homeassistant.core import callback @@ -54,8 +58,6 @@ class DeconzFlowHandler(config_entries.ConfigFlow): If more than one bridge is found let user choose bridge to link. If no bridge is found allow user to manually input configuration. """ - from pydeconz.utils import async_discovery - if user_input is not None: for bridge in self.bridges: if bridge[CONF_HOST] == user_input[CONF_HOST]: @@ -101,8 +103,6 @@ class DeconzFlowHandler(config_entries.ConfigFlow): async def async_step_link(self, user_input=None): """Attempt to link with the deCONZ bridge.""" - from pydeconz.errors import ResponseError, RequestError - from pydeconz.utils import async_get_api_key errors = {} if user_input is not None: @@ -127,8 +127,6 @@ class DeconzFlowHandler(config_entries.ConfigFlow): async def _create_entry(self): """Create entry for gateway.""" - from pydeconz.utils import async_get_bridgeid - if CONF_BRIDGEID not in self.deconz_config: session = aiohttp_client.async_get_clientsession(self.hass) diff --git a/homeassistant/components/deconz/cover.py b/homeassistant/components/deconz/cover.py index aa29e8c6b58..a89e7fdd595 100644 --- a/homeassistant/components/deconz/cover.py +++ b/homeassistant/components/deconz/cover.py @@ -14,7 +14,7 @@ ZIGBEE_SPEC = ['lumi.curtain'] async def async_setup_platform( hass, config, async_add_entities, discovery_info=None): - """Unsupported way of setting up deCONZ covers.""" + """Old way of setting up deCONZ platforms.""" pass diff --git a/homeassistant/components/deconz/deconz_device.py b/homeassistant/components/deconz/deconz_device.py index 73ac2499cd3..90a5c8a3dde 100644 --- a/homeassistant/components/deconz/deconz_device.py +++ b/homeassistant/components/deconz/deconz_device.py @@ -31,7 +31,7 @@ class DeconzDevice(Entity): self.unsub_dispatcher() @callback - def async_update_callback(self, reason): + def async_update_callback(self, force_update=False): """Update the device's state.""" self.async_schedule_update_ha_state() diff --git a/homeassistant/components/deconz/gateway.py b/homeassistant/components/deconz/gateway.py index 46078ea6648..f5d398fcd2f 100644 --- a/homeassistant/components/deconz/gateway.py +++ b/homeassistant/components/deconz/gateway.py @@ -2,6 +2,9 @@ import asyncio import async_timeout +from pydeconz import DeconzSession, errors +from pydeconz.sensor import Switch + from homeassistant.exceptions import ConfigEntryNotReady from homeassistant.const import CONF_EVENT, CONF_HOST, CONF_ID from homeassistant.core import EventOrigin, callback @@ -126,8 +129,7 @@ class DeconzGateway: def async_connection_status_callback(self, available): """Handle signals of gateway connection status.""" self.available = available - async_dispatcher_send(self.hass, self.event_reachable, - {'state': True, 'attr': 'reachable'}) + async_dispatcher_send(self.hass, self.event_reachable, True) @callback def async_event_new_device(self, device_type): @@ -145,9 +147,8 @@ class DeconzGateway: @callback def async_add_remote(self, sensors): """Set up remote from deCONZ.""" - from pydeconz.sensor import SWITCH as DECONZ_REMOTE for sensor in sensors: - if sensor.type in DECONZ_REMOTE and \ + if sensor.type in Switch.ZHATYPE and \ not (not self.allow_clip_sensor and sensor.type.startswith('CLIP')): self.events.append(DeconzEvent(self.hass, sensor)) @@ -187,8 +188,6 @@ class DeconzGateway: async def get_gateway(hass, config, async_add_device_callback, async_connection_status_callback): """Create a gateway object and verify configuration.""" - from pydeconz import DeconzSession, errors - session = aiohttp_client.async_get_clientsession(hass) deconz = DeconzSession(hass.loop, session, **config, @@ -232,8 +231,8 @@ class DeconzEvent: self._device = None @callback - def async_update_callback(self, reason): + def async_update_callback(self, force_update=False): """Fire the event if reason is that state is updated.""" - if reason['state']: + if 'state' in self._device.changed_keys: data = {CONF_ID: self._id, CONF_EVENT: self._device.state} self._hass.bus.async_fire(self._event, data, EventOrigin.remote) diff --git a/homeassistant/components/deconz/light.py b/homeassistant/components/deconz/light.py index c195703c36a..a3328ca8042 100644 --- a/homeassistant/components/deconz/light.py +++ b/homeassistant/components/deconz/light.py @@ -15,7 +15,7 @@ from .gateway import get_gateway_from_config_entry async def async_setup_platform( hass, config, async_add_entities, discovery_info=None): - """Old way of setting up deCONZ lights and group.""" + """Old way of setting up deCONZ platforms.""" pass diff --git a/homeassistant/components/deconz/manifest.json b/homeassistant/components/deconz/manifest.json index 0692bd444b8..08a01cd1379 100644 --- a/homeassistant/components/deconz/manifest.json +++ b/homeassistant/components/deconz/manifest.json @@ -4,7 +4,7 @@ "config_flow": true, "documentation": "https://www.home-assistant.io/components/deconz", "requirements": [ - "pydeconz==58" + "pydeconz==59" ], "dependencies": [], "codeowners": [ diff --git a/homeassistant/components/deconz/scene.py b/homeassistant/components/deconz/scene.py index d2e7f6719e9..c8cfa9674c5 100644 --- a/homeassistant/components/deconz/scene.py +++ b/homeassistant/components/deconz/scene.py @@ -9,7 +9,7 @@ from .gateway import get_gateway_from_config_entry async def async_setup_platform( hass, config, async_add_entities, discovery_info=None): - """Old way of setting up deCONZ scenes.""" + """Old way of setting up deCONZ platforms.""" pass diff --git a/homeassistant/components/deconz/sensor.py b/homeassistant/components/deconz/sensor.py index 9f1e87db4ba..efdb8ad8091 100644 --- a/homeassistant/components/deconz/sensor.py +++ b/homeassistant/components/deconz/sensor.py @@ -1,6 +1,8 @@ """Support for deCONZ sensors.""" +from pydeconz.sensor import LightLevel, Switch + from homeassistant.const import ( - ATTR_BATTERY_LEVEL, ATTR_VOLTAGE, DEVICE_CLASS_BATTERY) + ATTR_BATTERY_LEVEL, ATTR_TEMPERATURE, ATTR_VOLTAGE, DEVICE_CLASS_BATTERY) from homeassistant.core import callback from homeassistant.helpers.dispatcher import async_dispatcher_connect from homeassistant.util import slugify @@ -16,7 +18,7 @@ ATTR_EVENT_ID = 'event_id' async def async_setup_platform( hass, config, async_add_entities, discovery_info=None): - """Old way of setting up deCONZ sensors.""" + """Old way of setting up deCONZ platforms.""" pass @@ -27,17 +29,15 @@ async def async_setup_entry(hass, config_entry, async_add_entities): @callback def async_add_sensor(sensors): """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 and \ + if not sensor.BINARY and \ not (not gateway.allow_clip_sensor and sensor.type.startswith('CLIP')): - if sensor.type in DECONZ_REMOTE: + if sensor.type in Switch.ZHATYPE: if sensor.battery: entities.append(DeconzBattery(sensor, gateway)) @@ -56,16 +56,11 @@ class DeconzSensor(DeconzDevice): """Representation of a deCONZ sensor.""" @callback - def async_update_callback(self, reason): - """Update the sensor's state. - - If reason is that state is updated, - or reachable has changed or battery has changed. - """ - if reason['state'] or \ - 'reachable' in reason['attr'] or \ - 'battery' in reason['attr'] or \ - 'on' in reason['attr']: + def async_update_callback(self, force_update=False): + """Update the sensor's state.""" + changed = set(self._device.changed_keys) + keys = {'battery', 'on', 'reachable', 'state'} + if force_update or any(key in changed for key in keys): self.async_schedule_update_ha_state() @property @@ -76,34 +71,42 @@ class DeconzSensor(DeconzDevice): @property def device_class(self): """Return the class of the sensor.""" - return self._device.sensor_class + return self._device.SENSOR_CLASS @property def icon(self): """Return the icon to use in the frontend.""" - return self._device.sensor_icon + return self._device.SENSOR_ICON @property def unit_of_measurement(self): """Return the unit of measurement of this sensor.""" - return self._device.sensor_unit + return self._device.SENSOR_UNIT @property def device_state_attributes(self): """Return the state attributes of the sensor.""" - from pydeconz.sensor import LIGHTLEVEL attr = {} if self._device.battery: attr[ATTR_BATTERY_LEVEL] = self._device.battery + if self._device.on is not None: attr[ATTR_ON] = self._device.on - if self._device.type in LIGHTLEVEL and self._device.dark is not None: + + if self._device.secondary_temperature is not None: + attr[ATTR_TEMPERATURE] = self._device.secondary_temperature + + if self._device.type in LightLevel.ZHATYPE and \ + self._device.dark is not None: attr[ATTR_DARK] = self._device.dark + if self.unit_of_measurement == 'Watts': attr[ATTR_CURRENT] = self._device.current attr[ATTR_VOLTAGE] = self._device.voltage - if self._device.sensor_class == 'daylight': + + if self._device.SENSOR_CLASS == 'daylight': attr[ATTR_DAYLIGHT] = self._device.daylight + return attr @@ -118,9 +121,11 @@ class DeconzBattery(DeconzDevice): self._unit_of_measurement = "%" @callback - def async_update_callback(self, reason): + def async_update_callback(self, force_update=False): """Update the battery's state, if needed.""" - if 'reachable' in reason['attr'] or 'battery' in reason['attr']: + changed = set(self._device.changed_keys) + keys = {'battery', 'reachable'} + if force_update or any(key in changed for key in keys): self.async_schedule_update_ha_state() @property diff --git a/homeassistant/components/deconz/switch.py b/homeassistant/components/deconz/switch.py index c399f5da128..dd06dba9583 100644 --- a/homeassistant/components/deconz/switch.py +++ b/homeassistant/components/deconz/switch.py @@ -10,7 +10,7 @@ from .gateway import get_gateway_from_config_entry async def async_setup_platform( hass, config, async_add_entities, discovery_info=None): - """Old way of setting up deCONZ switches.""" + """Old way of setting up deCONZ platforms.""" pass diff --git a/requirements_all.txt b/requirements_all.txt index b6824d3d894..d5cff9366b2 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1048,7 +1048,7 @@ pydaikin==1.4.6 pydanfossair==0.1.0 # homeassistant.components.deconz -pydeconz==58 +pydeconz==59 # homeassistant.components.zwave pydispatcher==2.0.5 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 137a1662b00..f551e9ddc34 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -230,7 +230,7 @@ pyHS100==0.3.5 pyblackbird==0.5 # homeassistant.components.deconz -pydeconz==58 +pydeconz==59 # homeassistant.components.zwave pydispatcher==2.0.5 diff --git a/tests/components/deconz/test_binary_sensor.py b/tests/components/deconz/test_binary_sensor.py index 1aee53f43c2..89629a07cfa 100644 --- a/tests/components/deconz/test_binary_sensor.py +++ b/tests/components/deconz/test_binary_sensor.py @@ -1,6 +1,8 @@ """deCONZ binary sensor platform tests.""" from unittest.mock import Mock, patch +from tests.common import mock_coro + from homeassistant import config_entries from homeassistant.components import deconz from homeassistant.helpers.dispatcher import async_dispatcher_send @@ -8,8 +10,6 @@ from homeassistant.setup import async_setup_component import homeassistant.components.binary_sensor as binary_sensor -from tests.common import mock_coro - SENSOR = { "1": { @@ -104,6 +104,7 @@ async def test_add_new_sensor(hass): sensor = Mock() sensor.name = 'name' sensor.type = 'ZHAPresence' + sensor.BINARY = True sensor.register_async_callback = Mock() async_dispatcher_send( hass, gateway.async_event_new_device('sensor'), [sensor]) diff --git a/tests/components/deconz/test_climate.py b/tests/components/deconz/test_climate.py index a5f4d2bb79b..407f5d92871 100644 --- a/tests/components/deconz/test_climate.py +++ b/tests/components/deconz/test_climate.py @@ -1,4 +1,5 @@ """deCONZ climate platform tests.""" +from copy import deepcopy from unittest.mock import Mock, patch import asynctest @@ -18,9 +19,9 @@ SENSOR = { "id": "Climate 1 id", "name": "Climate 1 name", "type": "ZHAThermostat", - "state": {"on": True, "temperature": 2260}, + "state": {"on": True, "temperature": 2260, "valve": 30}, "config": {"battery": 100, "heatsetpoint": 2200, "mode": "auto", - "offset": 10, "reachable": True, "valve": 30}, + "offset": 10, "reachable": True}, "uniqueid": "00:00:00:00:00:00:00:00-00" }, "2": { @@ -97,7 +98,7 @@ async def test_no_sensors(hass): async def test_climate_devices(hass): """Test successful creation of sensor entities.""" - gateway = await setup_gateway(hass, {"sensors": SENSOR}) + gateway = await setup_gateway(hass, {"sensors": deepcopy(SENSOR)}) assert "climate.climate_1_name" in gateway.deconz_ids assert "sensor.sensor_2_name" not in gateway.deconz_ids assert len(hass.states.async_all()) == 1 @@ -138,7 +139,7 @@ async def test_climate_devices(hass): async def test_verify_state_update(hass): """Test that state update properly.""" - gateway = await setup_gateway(hass, {"sensors": SENSOR}) + gateway = await setup_gateway(hass, {"sensors": deepcopy(SENSOR)}) assert "climate.climate_1_name" in gateway.deconz_ids thermostat = hass.states.get('climate.climate_1_name') @@ -149,7 +150,7 @@ async def test_verify_state_update(hass): "e": "changed", "r": "sensors", "id": "1", - "config": {"on": False} + "state": {"on": False} } gateway.api.async_event_handler(state_update) @@ -158,6 +159,8 @@ async def test_verify_state_update(hass): thermostat = hass.states.get('climate.climate_1_name') assert thermostat.state == 'off' + assert gateway.api.sensors['1'].changed_keys == \ + {'state', 'r', 't', 'on', 'e', 'id'} async def test_add_new_climate_device(hass): diff --git a/tests/components/deconz/test_config_flow.py b/tests/components/deconz/test_config_flow.py index ada506be428..46b0084b01b 100644 --- a/tests/components/deconz/test_config_flow.py +++ b/tests/components/deconz/test_config_flow.py @@ -43,7 +43,7 @@ async def test_flow_works(hass, aioclient_mock): async def test_user_step_bridge_discovery_fails(hass, aioclient_mock): """Test config flow works when discovery fails.""" - with patch('pydeconz.utils.async_discovery', + with patch('homeassistant.components.deconz.config_flow.async_discovery', side_effect=asyncio.TimeoutError): result = await hass.config_entries.flow.async_init( config_flow.DOMAIN, @@ -158,8 +158,9 @@ async def test_link_no_api_key(hass): config_flow.CONF_PORT: 80 } - with patch('pydeconz.utils.async_get_api_key', - side_effect=pydeconz.errors.ResponseError): + with patch( + 'homeassistant.components.deconz.config_flow.async_get_api_key', + side_effect=pydeconz.errors.ResponseError): result = await flow.async_step_link(user_input={}) assert result['type'] == 'form' @@ -275,8 +276,9 @@ async def test_create_entry_timeout(hass, aioclient_mock): config_flow.CONF_API_KEY: '1234567890ABCDEF' } - with patch('pydeconz.utils.async_get_bridgeid', - side_effect=asyncio.TimeoutError): + with patch( + 'homeassistant.components.deconz.config_flow.async_get_bridgeid', + side_effect=asyncio.TimeoutError): result = await flow._create_entry() assert result['type'] == 'abort' diff --git a/tests/components/deconz/test_gateway.py b/tests/components/deconz/test_gateway.py index 6006ff66898..46107e1dd6c 100644 --- a/tests/components/deconz/test_gateway.py +++ b/tests/components/deconz/test_gateway.py @@ -223,7 +223,8 @@ async def test_update_event(): remote.name = 'Name' event = gateway.DeconzEvent(hass, remote) - event.async_update_callback({'state': True}) + remote.changed_keys = {'state': True} + event.async_update_callback() assert len(hass.bus.async_fire.mock_calls) == 1 diff --git a/tests/components/deconz/test_sensor.py b/tests/components/deconz/test_sensor.py index 41bb7b362f5..7ed8bef093e 100644 --- a/tests/components/deconz/test_sensor.py +++ b/tests/components/deconz/test_sensor.py @@ -1,6 +1,8 @@ """deCONZ sensor platform tests.""" from unittest.mock import Mock, patch +from tests.common import mock_coro + from homeassistant import config_entries from homeassistant.components import deconz from homeassistant.helpers.dispatcher import async_dispatcher_send @@ -8,8 +10,6 @@ from homeassistant.setup import async_setup_component import homeassistant.components.sensor as sensor -from tests.common import mock_coro - SENSOR = { "1": { @@ -142,6 +142,7 @@ async def test_add_new_sensor(hass): sensor = Mock() sensor.name = 'name' sensor.type = 'ZHATemperature' + sensor.BINARY = False sensor.register_async_callback = Mock() async_dispatcher_send( hass, gateway.async_event_new_device('sensor'), [sensor])