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
This commit is contained in:
Robert Svensson 2019-05-27 06:56:00 +02:00 committed by GitHub
parent 0ba54ee9b7
commit 31b2f331db
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
19 changed files with 104 additions and 83 deletions

View file

@ -164,6 +164,7 @@ async def async_unload_entry(hass, config_entry):
if not hass.data[DOMAIN]: if not hass.data[DOMAIN]:
hass.services.async_remove(DOMAIN, SERVICE_DECONZ) hass.services.async_remove(DOMAIN, SERVICE_DECONZ)
hass.services.async_remove(DOMAIN, SERVICE_DEVICE_REFRESH) hass.services.async_remove(DOMAIN, SERVICE_DEVICE_REFRESH)
elif gateway.master: elif gateway.master:
await async_populate_options(hass, config_entry) await async_populate_options(hass, config_entry)
new_master_gateway = next(iter(hass.data[DOMAIN].values())) new_master_gateway = next(iter(hass.data[DOMAIN].values()))

View file

@ -1,6 +1,8 @@
"""Support for deCONZ binary sensors.""" """Support for deCONZ binary sensors."""
from pydeconz.sensor import Presence, Vibration
from homeassistant.components.binary_sensor import BinarySensorDevice 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.core import callback
from homeassistant.helpers.dispatcher import async_dispatcher_connect from homeassistant.helpers.dispatcher import async_dispatcher_connect
@ -15,7 +17,7 @@ ATTR_VIBRATIONSTRENGTH = 'vibrationstrength'
async def async_setup_platform( async def async_setup_platform(
hass, config, async_add_entities, discovery_info=None): hass, config, async_add_entities, discovery_info=None):
"""Old way of setting up deCONZ binary sensors.""" """Old way of setting up deCONZ platforms."""
pass pass
@ -26,12 +28,11 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
@callback @callback
def async_add_sensor(sensors): def async_add_sensor(sensors):
"""Add binary sensor from deCONZ.""" """Add binary sensor from deCONZ."""
from pydeconz.sensor import DECONZ_BINARY_SENSOR
entities = [] entities = []
for sensor in sensors: for sensor in sensors:
if sensor.type in DECONZ_BINARY_SENSOR and \ if sensor.BINARY and \
not (not gateway.allow_clip_sensor and not (not gateway.allow_clip_sensor and
sensor.type.startswith('CLIP')): sensor.type.startswith('CLIP')):
@ -49,16 +50,11 @@ class DeconzBinarySensor(DeconzDevice, BinarySensorDevice):
"""Representation of a deCONZ binary sensor.""" """Representation of a deCONZ binary sensor."""
@callback @callback
def async_update_callback(self, reason): def async_update_callback(self, force_update=False):
"""Update the sensor's state. """Update the sensor's state."""
changed = set(self._device.changed_keys)
If reason is that state is updated, keys = {'battery', 'on', 'reachable', 'state'}
or reachable has changed or battery has changed. if force_update or any(key in changed for key in keys):
"""
if reason['state'] or \
'reachable' in reason['attr'] or \
'battery' in reason['attr'] or \
'on' in reason['attr']:
self.async_schedule_update_ha_state() self.async_schedule_update_ha_state()
@property @property
@ -69,26 +65,33 @@ class DeconzBinarySensor(DeconzDevice, BinarySensorDevice):
@property @property
def device_class(self): def device_class(self):
"""Return the class of the sensor.""" """Return the class of the sensor."""
return self._device.sensor_class return self._device.SENSOR_CLASS
@property @property
def icon(self): def icon(self):
"""Return the icon to use in the frontend.""" """Return the icon to use in the frontend."""
return self._device.sensor_icon return self._device.SENSOR_ICON
@property @property
def device_state_attributes(self): def device_state_attributes(self):
"""Return the state attributes of the sensor.""" """Return the state attributes of the sensor."""
from pydeconz.sensor import PRESENCE, VIBRATION
attr = {} attr = {}
if self._device.battery: if self._device.battery:
attr[ATTR_BATTERY_LEVEL] = self._device.battery attr[ATTR_BATTERY_LEVEL] = self._device.battery
if self._device.on is not None: if self._device.on is not None:
attr[ATTR_ON] = self._device.on 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 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_ORIENTATION] = self._device.orientation
attr[ATTR_TILTANGLE] = self._device.tiltangle attr[ATTR_TILTANGLE] = self._device.tiltangle
attr[ATTR_VIBRATIONSTRENGTH] = self._device.vibrationstrength attr[ATTR_VIBRATIONSTRENGTH] = self._device.vibrationstrength
return attr return attr

View file

@ -1,4 +1,6 @@
"""Support for deCONZ climate devices.""" """Support for deCONZ climate devices."""
from pydeconz.sensor import Thermostat
from homeassistant.components.climate import ClimateDevice from homeassistant.components.climate import ClimateDevice
from homeassistant.components.climate.const import ( from homeassistant.components.climate.const import (
SUPPORT_ON_OFF, SUPPORT_TARGET_TEMPERATURE) SUPPORT_ON_OFF, SUPPORT_TARGET_TEMPERATURE)
@ -12,6 +14,12 @@ from .deconz_device import DeconzDevice
from .gateway import get_gateway_from_config_entry 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): async def async_setup_entry(hass, config_entry, async_add_entities):
"""Set up the deCONZ climate devices. """Set up the deCONZ climate devices.
@ -22,12 +30,11 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
@callback @callback
def async_add_climate(sensors): def async_add_climate(sensors):
"""Add climate devices from deCONZ.""" """Add climate devices from deCONZ."""
from pydeconz.sensor import THERMOSTAT
entities = [] entities = []
for sensor in sensors: for sensor in sensors:
if sensor.type in THERMOSTAT and \ if sensor.type in Thermostat.ZHATYPE and \
not (not gateway.allow_clip_sensor and not (not gateway.allow_clip_sensor and
sensor.type.startswith('CLIP')): sensor.type.startswith('CLIP')):
@ -59,7 +66,7 @@ class DeconzThermostat(DeconzDevice, ClimateDevice):
@property @property
def is_on(self): def is_on(self):
"""Return true if on.""" """Return true if on."""
return self._device.on return self._device.state_on
async def async_turn_on(self): async def async_turn_on(self):
"""Turn on switch.""" """Turn on switch."""

View file

@ -4,6 +4,10 @@ import asyncio
import async_timeout import async_timeout
import voluptuous as vol 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 import config_entries
from homeassistant.const import CONF_API_KEY, CONF_HOST, CONF_PORT from homeassistant.const import CONF_API_KEY, CONF_HOST, CONF_PORT
from homeassistant.core import callback 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 more than one bridge is found let user choose bridge to link.
If no bridge is found allow user to manually input configuration. If no bridge is found allow user to manually input configuration.
""" """
from pydeconz.utils import async_discovery
if user_input is not None: if user_input is not None:
for bridge in self.bridges: for bridge in self.bridges:
if bridge[CONF_HOST] == user_input[CONF_HOST]: 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): async def async_step_link(self, user_input=None):
"""Attempt to link with the deCONZ bridge.""" """Attempt to link with the deCONZ bridge."""
from pydeconz.errors import ResponseError, RequestError
from pydeconz.utils import async_get_api_key
errors = {} errors = {}
if user_input is not None: if user_input is not None:
@ -127,8 +127,6 @@ class DeconzFlowHandler(config_entries.ConfigFlow):
async def _create_entry(self): async def _create_entry(self):
"""Create entry for gateway.""" """Create entry for gateway."""
from pydeconz.utils import async_get_bridgeid
if CONF_BRIDGEID not in self.deconz_config: if CONF_BRIDGEID not in self.deconz_config:
session = aiohttp_client.async_get_clientsession(self.hass) session = aiohttp_client.async_get_clientsession(self.hass)

View file

@ -14,7 +14,7 @@ ZIGBEE_SPEC = ['lumi.curtain']
async def async_setup_platform( async def async_setup_platform(
hass, config, async_add_entities, discovery_info=None): hass, config, async_add_entities, discovery_info=None):
"""Unsupported way of setting up deCONZ covers.""" """Old way of setting up deCONZ platforms."""
pass pass

View file

@ -31,7 +31,7 @@ class DeconzDevice(Entity):
self.unsub_dispatcher() self.unsub_dispatcher()
@callback @callback
def async_update_callback(self, reason): def async_update_callback(self, force_update=False):
"""Update the device's state.""" """Update the device's state."""
self.async_schedule_update_ha_state() self.async_schedule_update_ha_state()

View file

@ -2,6 +2,9 @@
import asyncio import asyncio
import async_timeout import async_timeout
from pydeconz import DeconzSession, errors
from pydeconz.sensor import Switch
from homeassistant.exceptions import ConfigEntryNotReady from homeassistant.exceptions import ConfigEntryNotReady
from homeassistant.const import CONF_EVENT, CONF_HOST, CONF_ID from homeassistant.const import CONF_EVENT, CONF_HOST, CONF_ID
from homeassistant.core import EventOrigin, callback from homeassistant.core import EventOrigin, callback
@ -126,8 +129,7 @@ class DeconzGateway:
def async_connection_status_callback(self, available): def async_connection_status_callback(self, available):
"""Handle signals of gateway connection status.""" """Handle signals of gateway connection status."""
self.available = available self.available = available
async_dispatcher_send(self.hass, self.event_reachable, async_dispatcher_send(self.hass, self.event_reachable, True)
{'state': True, 'attr': 'reachable'})
@callback @callback
def async_event_new_device(self, device_type): def async_event_new_device(self, device_type):
@ -145,9 +147,8 @@ class DeconzGateway:
@callback @callback
def async_add_remote(self, sensors): def async_add_remote(self, sensors):
"""Set up remote from deCONZ.""" """Set up remote from deCONZ."""
from pydeconz.sensor import SWITCH as DECONZ_REMOTE
for sensor in sensors: 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 not (not self.allow_clip_sensor and
sensor.type.startswith('CLIP')): sensor.type.startswith('CLIP')):
self.events.append(DeconzEvent(self.hass, sensor)) self.events.append(DeconzEvent(self.hass, sensor))
@ -187,8 +188,6 @@ class DeconzGateway:
async def get_gateway(hass, config, async_add_device_callback, async def get_gateway(hass, config, async_add_device_callback,
async_connection_status_callback): async_connection_status_callback):
"""Create a gateway object and verify configuration.""" """Create a gateway object and verify configuration."""
from pydeconz import DeconzSession, errors
session = aiohttp_client.async_get_clientsession(hass) session = aiohttp_client.async_get_clientsession(hass)
deconz = DeconzSession(hass.loop, session, **config, deconz = DeconzSession(hass.loop, session, **config,
@ -232,8 +231,8 @@ class DeconzEvent:
self._device = None self._device = None
@callback @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.""" """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} data = {CONF_ID: self._id, CONF_EVENT: self._device.state}
self._hass.bus.async_fire(self._event, data, EventOrigin.remote) self._hass.bus.async_fire(self._event, data, EventOrigin.remote)

View file

@ -15,7 +15,7 @@ from .gateway import get_gateway_from_config_entry
async def async_setup_platform( async def async_setup_platform(
hass, config, async_add_entities, discovery_info=None): 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 pass

View file

@ -4,7 +4,7 @@
"config_flow": true, "config_flow": true,
"documentation": "https://www.home-assistant.io/components/deconz", "documentation": "https://www.home-assistant.io/components/deconz",
"requirements": [ "requirements": [
"pydeconz==58" "pydeconz==59"
], ],
"dependencies": [], "dependencies": [],
"codeowners": [ "codeowners": [

View file

@ -9,7 +9,7 @@ from .gateway import get_gateway_from_config_entry
async def async_setup_platform( async def async_setup_platform(
hass, config, async_add_entities, discovery_info=None): hass, config, async_add_entities, discovery_info=None):
"""Old way of setting up deCONZ scenes.""" """Old way of setting up deCONZ platforms."""
pass pass

View file

@ -1,6 +1,8 @@
"""Support for deCONZ sensors.""" """Support for deCONZ sensors."""
from pydeconz.sensor import LightLevel, Switch
from homeassistant.const import ( 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.core import callback
from homeassistant.helpers.dispatcher import async_dispatcher_connect from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.util import slugify from homeassistant.util import slugify
@ -16,7 +18,7 @@ ATTR_EVENT_ID = 'event_id'
async def async_setup_platform( async def async_setup_platform(
hass, config, async_add_entities, discovery_info=None): hass, config, async_add_entities, discovery_info=None):
"""Old way of setting up deCONZ sensors.""" """Old way of setting up deCONZ platforms."""
pass pass
@ -27,17 +29,15 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
@callback @callback
def async_add_sensor(sensors): def async_add_sensor(sensors):
"""Add sensors from deCONZ.""" """Add sensors from deCONZ."""
from pydeconz.sensor import (
DECONZ_SENSOR, SWITCH as DECONZ_REMOTE)
entities = [] entities = []
for sensor in sensors: for sensor in sensors:
if sensor.type in DECONZ_SENSOR and \ if not sensor.BINARY and \
not (not gateway.allow_clip_sensor and not (not gateway.allow_clip_sensor and
sensor.type.startswith('CLIP')): sensor.type.startswith('CLIP')):
if sensor.type in DECONZ_REMOTE: if sensor.type in Switch.ZHATYPE:
if sensor.battery: if sensor.battery:
entities.append(DeconzBattery(sensor, gateway)) entities.append(DeconzBattery(sensor, gateway))
@ -56,16 +56,11 @@ class DeconzSensor(DeconzDevice):
"""Representation of a deCONZ sensor.""" """Representation of a deCONZ sensor."""
@callback @callback
def async_update_callback(self, reason): def async_update_callback(self, force_update=False):
"""Update the sensor's state. """Update the sensor's state."""
changed = set(self._device.changed_keys)
If reason is that state is updated, keys = {'battery', 'on', 'reachable', 'state'}
or reachable has changed or battery has changed. if force_update or any(key in changed for key in keys):
"""
if reason['state'] or \
'reachable' in reason['attr'] or \
'battery' in reason['attr'] or \
'on' in reason['attr']:
self.async_schedule_update_ha_state() self.async_schedule_update_ha_state()
@property @property
@ -76,34 +71,42 @@ class DeconzSensor(DeconzDevice):
@property @property
def device_class(self): def device_class(self):
"""Return the class of the sensor.""" """Return the class of the sensor."""
return self._device.sensor_class return self._device.SENSOR_CLASS
@property @property
def icon(self): def icon(self):
"""Return the icon to use in the frontend.""" """Return the icon to use in the frontend."""
return self._device.sensor_icon return self._device.SENSOR_ICON
@property @property
def unit_of_measurement(self): def unit_of_measurement(self):
"""Return the unit of measurement of this sensor.""" """Return the unit of measurement of this sensor."""
return self._device.sensor_unit return self._device.SENSOR_UNIT
@property @property
def device_state_attributes(self): def device_state_attributes(self):
"""Return the state attributes of the sensor.""" """Return the state attributes of the sensor."""
from pydeconz.sensor import LIGHTLEVEL
attr = {} attr = {}
if self._device.battery: if self._device.battery:
attr[ATTR_BATTERY_LEVEL] = self._device.battery attr[ATTR_BATTERY_LEVEL] = self._device.battery
if self._device.on is not None: if self._device.on is not None:
attr[ATTR_ON] = self._device.on 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 attr[ATTR_DARK] = self._device.dark
if self.unit_of_measurement == 'Watts': if self.unit_of_measurement == 'Watts':
attr[ATTR_CURRENT] = self._device.current attr[ATTR_CURRENT] = self._device.current
attr[ATTR_VOLTAGE] = self._device.voltage attr[ATTR_VOLTAGE] = self._device.voltage
if self._device.sensor_class == 'daylight':
if self._device.SENSOR_CLASS == 'daylight':
attr[ATTR_DAYLIGHT] = self._device.daylight attr[ATTR_DAYLIGHT] = self._device.daylight
return attr return attr
@ -118,9 +121,11 @@ class DeconzBattery(DeconzDevice):
self._unit_of_measurement = "%" self._unit_of_measurement = "%"
@callback @callback
def async_update_callback(self, reason): def async_update_callback(self, force_update=False):
"""Update the battery's state, if needed.""" """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() self.async_schedule_update_ha_state()
@property @property

View file

@ -10,7 +10,7 @@ from .gateway import get_gateway_from_config_entry
async def async_setup_platform( async def async_setup_platform(
hass, config, async_add_entities, discovery_info=None): hass, config, async_add_entities, discovery_info=None):
"""Old way of setting up deCONZ switches.""" """Old way of setting up deCONZ platforms."""
pass pass

View file

@ -1048,7 +1048,7 @@ pydaikin==1.4.6
pydanfossair==0.1.0 pydanfossair==0.1.0
# homeassistant.components.deconz # homeassistant.components.deconz
pydeconz==58 pydeconz==59
# homeassistant.components.zwave # homeassistant.components.zwave
pydispatcher==2.0.5 pydispatcher==2.0.5

View file

@ -230,7 +230,7 @@ pyHS100==0.3.5
pyblackbird==0.5 pyblackbird==0.5
# homeassistant.components.deconz # homeassistant.components.deconz
pydeconz==58 pydeconz==59
# homeassistant.components.zwave # homeassistant.components.zwave
pydispatcher==2.0.5 pydispatcher==2.0.5

View file

@ -1,6 +1,8 @@
"""deCONZ binary sensor platform tests.""" """deCONZ binary sensor platform tests."""
from unittest.mock import Mock, patch from unittest.mock import Mock, patch
from tests.common import mock_coro
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 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 import homeassistant.components.binary_sensor as binary_sensor
from tests.common import mock_coro
SENSOR = { SENSOR = {
"1": { "1": {
@ -104,6 +104,7 @@ async def test_add_new_sensor(hass):
sensor = Mock() sensor = Mock()
sensor.name = 'name' sensor.name = 'name'
sensor.type = 'ZHAPresence' sensor.type = 'ZHAPresence'
sensor.BINARY = True
sensor.register_async_callback = Mock() sensor.register_async_callback = Mock()
async_dispatcher_send( async_dispatcher_send(
hass, gateway.async_event_new_device('sensor'), [sensor]) hass, gateway.async_event_new_device('sensor'), [sensor])

View file

@ -1,4 +1,5 @@
"""deCONZ climate platform tests.""" """deCONZ climate platform tests."""
from copy import deepcopy
from unittest.mock import Mock, patch from unittest.mock import Mock, patch
import asynctest import asynctest
@ -18,9 +19,9 @@ SENSOR = {
"id": "Climate 1 id", "id": "Climate 1 id",
"name": "Climate 1 name", "name": "Climate 1 name",
"type": "ZHAThermostat", "type": "ZHAThermostat",
"state": {"on": True, "temperature": 2260}, "state": {"on": True, "temperature": 2260, "valve": 30},
"config": {"battery": 100, "heatsetpoint": 2200, "mode": "auto", "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" "uniqueid": "00:00:00:00:00:00:00:00-00"
}, },
"2": { "2": {
@ -97,7 +98,7 @@ async def test_no_sensors(hass):
async def test_climate_devices(hass): async def test_climate_devices(hass):
"""Test successful creation of sensor entities.""" """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 "climate.climate_1_name" in gateway.deconz_ids
assert "sensor.sensor_2_name" not in gateway.deconz_ids assert "sensor.sensor_2_name" not in gateway.deconz_ids
assert len(hass.states.async_all()) == 1 assert len(hass.states.async_all()) == 1
@ -138,7 +139,7 @@ async def test_climate_devices(hass):
async def test_verify_state_update(hass): async def test_verify_state_update(hass):
"""Test that state update properly.""" """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 assert "climate.climate_1_name" in gateway.deconz_ids
thermostat = hass.states.get('climate.climate_1_name') thermostat = hass.states.get('climate.climate_1_name')
@ -149,7 +150,7 @@ async def test_verify_state_update(hass):
"e": "changed", "e": "changed",
"r": "sensors", "r": "sensors",
"id": "1", "id": "1",
"config": {"on": False} "state": {"on": False}
} }
gateway.api.async_event_handler(state_update) 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') thermostat = hass.states.get('climate.climate_1_name')
assert thermostat.state == 'off' 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): async def test_add_new_climate_device(hass):

View file

@ -43,7 +43,7 @@ async def test_flow_works(hass, aioclient_mock):
async def test_user_step_bridge_discovery_fails(hass, aioclient_mock): async def test_user_step_bridge_discovery_fails(hass, aioclient_mock):
"""Test config flow works when discovery fails.""" """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): side_effect=asyncio.TimeoutError):
result = await hass.config_entries.flow.async_init( result = await hass.config_entries.flow.async_init(
config_flow.DOMAIN, config_flow.DOMAIN,
@ -158,8 +158,9 @@ async def test_link_no_api_key(hass):
config_flow.CONF_PORT: 80 config_flow.CONF_PORT: 80
} }
with patch('pydeconz.utils.async_get_api_key', with patch(
side_effect=pydeconz.errors.ResponseError): 'homeassistant.components.deconz.config_flow.async_get_api_key',
side_effect=pydeconz.errors.ResponseError):
result = await flow.async_step_link(user_input={}) result = await flow.async_step_link(user_input={})
assert result['type'] == 'form' assert result['type'] == 'form'
@ -275,8 +276,9 @@ async def test_create_entry_timeout(hass, aioclient_mock):
config_flow.CONF_API_KEY: '1234567890ABCDEF' config_flow.CONF_API_KEY: '1234567890ABCDEF'
} }
with patch('pydeconz.utils.async_get_bridgeid', with patch(
side_effect=asyncio.TimeoutError): 'homeassistant.components.deconz.config_flow.async_get_bridgeid',
side_effect=asyncio.TimeoutError):
result = await flow._create_entry() result = await flow._create_entry()
assert result['type'] == 'abort' assert result['type'] == 'abort'

View file

@ -223,7 +223,8 @@ async def test_update_event():
remote.name = 'Name' remote.name = 'Name'
event = gateway.DeconzEvent(hass, remote) 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 assert len(hass.bus.async_fire.mock_calls) == 1

View file

@ -1,6 +1,8 @@
"""deCONZ sensor platform tests.""" """deCONZ sensor platform tests."""
from unittest.mock import Mock, patch from unittest.mock import Mock, patch
from tests.common import mock_coro
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 homeassistant.helpers.dispatcher import async_dispatcher_send
@ -8,8 +10,6 @@ from homeassistant.setup import async_setup_component
import homeassistant.components.sensor as sensor import homeassistant.components.sensor as sensor
from tests.common import mock_coro
SENSOR = { SENSOR = {
"1": { "1": {
@ -142,6 +142,7 @@ async def test_add_new_sensor(hass):
sensor = Mock() sensor = Mock()
sensor.name = 'name' sensor.name = 'name'
sensor.type = 'ZHATemperature' sensor.type = 'ZHATemperature'
sensor.BINARY = False
sensor.register_async_callback = Mock() sensor.register_async_callback = Mock()
async_dispatcher_send( async_dispatcher_send(
hass, gateway.async_event_new_device('sensor'), [sensor]) hass, gateway.async_event_new_device('sensor'), [sensor])