Merge pull request #13098 from home-assistant/release-0-65-3

0.65.3
This commit is contained in:
Paulus Schoutsen 2018-03-11 13:14:18 -07:00 committed by GitHub
commit 49d51e5040
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 86 additions and 49 deletions

View File

@ -49,8 +49,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
}) })
@asyncio.coroutine def setup_platform(hass, config, add_devices, discovery_info=None):
def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
"""Set up an Arlo IP Camera.""" """Set up an Arlo IP Camera."""
arlo = hass.data.get(DATA_ARLO) arlo = hass.data.get(DATA_ARLO)
if not arlo: if not arlo:
@ -60,7 +59,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
for camera in arlo.cameras: for camera in arlo.cameras:
cameras.append(ArloCam(hass, camera, config)) cameras.append(ArloCam(hass, camera, config))
async_add_devices(cameras, True) add_devices(cameras, True)
class ArloCam(Camera): class ArloCam(Camera):

View File

@ -20,7 +20,7 @@ from homeassistant.helpers.aiohttp_client import (
async_get_clientsession) async_get_clientsession)
import homeassistant.helpers.config_validation as cv import homeassistant.helpers.config_validation as cv
REQUIREMENTS = ['py-synology==0.1.5'] REQUIREMENTS = ['py-synology==0.2.0']
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)

View File

@ -229,7 +229,7 @@ class GenericThermostat(ClimateDevice):
"""List of available operation modes.""" """List of available operation modes."""
return self._operation_list return self._operation_list
def set_operation_mode(self, operation_mode): async def async_set_operation_mode(self, operation_mode):
"""Set operation mode.""" """Set operation mode."""
if operation_mode == STATE_HEAT: if operation_mode == STATE_HEAT:
self._current_operation = STATE_HEAT self._current_operation = STATE_HEAT

View File

@ -68,22 +68,18 @@ class TadoDeviceScanner(DeviceScanner):
self.websession = async_create_clientsession( self.websession = async_create_clientsession(
hass, cookie_jar=aiohttp.CookieJar(unsafe=True, loop=hass.loop)) hass, cookie_jar=aiohttp.CookieJar(unsafe=True, loop=hass.loop))
self.success_init = self._update_info() self.success_init = asyncio.run_coroutine_threadsafe(
self._async_update_info(), hass.loop
).result()
_LOGGER.info("Scanner initialized") _LOGGER.info("Scanner initialized")
@asyncio.coroutine async def async_scan_devices(self):
def async_scan_devices(self):
"""Scan for devices and return a list containing found device ids.""" """Scan for devices and return a list containing found device ids."""
info = self._update_info() await self._async_update_info()
# Don't yield if we got None
if info is not None:
yield from info
return [device.mac for device in self.last_results] return [device.mac for device in self.last_results]
@asyncio.coroutine async def async_get_device_name(self, device):
def async_get_device_name(self, device):
"""Return the name of the given device or None if we don't know.""" """Return the name of the given device or None if we don't know."""
filter_named = [result.name for result in self.last_results filter_named = [result.name for result in self.last_results
if result.mac == device] if result.mac == device]
@ -93,7 +89,7 @@ class TadoDeviceScanner(DeviceScanner):
return None return None
@Throttle(MIN_TIME_BETWEEN_SCANS) @Throttle(MIN_TIME_BETWEEN_SCANS)
def _update_info(self): async def _async_update_info(self):
""" """
Query Tado for device marked as at home. Query Tado for device marked as at home.
@ -111,14 +107,14 @@ class TadoDeviceScanner(DeviceScanner):
home_id=self.home_id, username=self.username, home_id=self.home_id, username=self.username,
password=self.password) password=self.password)
response = yield from self.websession.get(url) response = await self.websession.get(url)
if response.status != 200: if response.status != 200:
_LOGGER.warning( _LOGGER.warning(
"Error %d on %s.", response.status, self.tadoapiurl) "Error %d on %s.", response.status, self.tadoapiurl)
return return False
tado_json = yield from response.json() tado_json = await response.json()
except (asyncio.TimeoutError, aiohttp.ClientError): except (asyncio.TimeoutError, aiohttp.ClientError):
_LOGGER.error("Cannot load Tado data") _LOGGER.error("Cannot load Tado data")
@ -139,7 +135,7 @@ class TadoDeviceScanner(DeviceScanner):
self.last_results = last_results self.last_results = last_results
_LOGGER.info( _LOGGER.debug(
"Tado presence query successful, %d device(s) at home", "Tado presence query successful, %d device(s) at home",
len(self.last_results) len(self.last_results)
) )

View File

@ -17,7 +17,7 @@ import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.event import async_track_state_change from homeassistant.helpers.event import async_track_state_change
from homeassistant.helpers.script import Script from homeassistant.helpers.script import Script
REQUIREMENTS = ['xknx==0.8.4'] REQUIREMENTS = ['xknx==0.8.5']
DOMAIN = "knx" DOMAIN = "knx"
DATA_KNX = "data_knx" DATA_KNX = "data_knx"
@ -241,7 +241,7 @@ class KNXModule(object):
async def telegram_received_cb(self, telegram): async def telegram_received_cb(self, telegram):
"""Call invoked after a KNX telegram was received.""" """Call invoked after a KNX telegram was received."""
self.hass.bus.fire('knx_event', { self.hass.bus.fire('knx_event', {
'address': telegram.group_address.str(), 'address': str(telegram.group_address),
'data': telegram.payload.value 'data': telegram.payload.value
}) })
# False signals XKNX to proceed with processing telegrams. # False signals XKNX to proceed with processing telegrams.

View File

@ -261,10 +261,13 @@ class HueLight(Light):
"""Return true if device is on.""" """Return true if device is on."""
if self.is_group: if self.is_group:
return self.info['state']['any_on'] return self.info['state']['any_on']
elif self.allow_unreachable:
return self.info['state']['on'] return self.info['state']['on']
return self.info['state']['reachable'] and \
self.info['state']['on'] @property
def available(self):
"""Return if light is available."""
return (self.is_group or self.allow_unreachable or
self.info['state']['reachable'])
@property @property
def supported_features(self): def supported_features(self):

View File

@ -17,7 +17,7 @@ from homeassistant.const import CONF_HOST, CONF_NAME, CONF_PORT
import homeassistant.helpers.config_validation as cv import homeassistant.helpers.config_validation as cv
import homeassistant.util.color as color_util import homeassistant.util.color as color_util
REQUIREMENTS = ['iglo==1.2.6'] REQUIREMENTS = ['iglo==1.2.7']
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@ -89,7 +89,7 @@ class IGloLamp(Light):
@property @property
def effect_list(self): def effect_list(self):
"""Return the list of supported effects.""" """Return the list of supported effects."""
return self._lamp.effect_list return self._lamp.effect_list()
@property @property
def supported_features(self): def supported_features(self):

View File

@ -7,7 +7,6 @@ https://home-assistant.io/components/media_player.cast/
# pylint: disable=import-error # pylint: disable=import-error
import logging import logging
import threading import threading
import functools
import voluptuous as vol import voluptuous as vol
@ -35,7 +34,6 @@ CONF_IGNORE_CEC = 'ignore_cec'
CAST_SPLASH = 'https://home-assistant.io/images/cast/splash.png' CAST_SPLASH = 'https://home-assistant.io/images/cast/splash.png'
DEFAULT_PORT = 8009 DEFAULT_PORT = 8009
SOCKET_CLIENT_RETRIES = 10
SUPPORT_CAST = SUPPORT_PAUSE | SUPPORT_VOLUME_SET | SUPPORT_VOLUME_MUTE | \ SUPPORT_CAST = SUPPORT_PAUSE | SUPPORT_VOLUME_SET | SUPPORT_VOLUME_MUTE | \
SUPPORT_TURN_ON | SUPPORT_TURN_OFF | SUPPORT_PREVIOUS_TRACK | \ SUPPORT_TURN_ON | SUPPORT_TURN_OFF | SUPPORT_PREVIOUS_TRACK | \
@ -78,7 +76,7 @@ def _setup_internal_discovery(hass: HomeAssistantType) -> None:
try: try:
# pylint: disable=protected-access # pylint: disable=protected-access
chromecast = pychromecast._get_chromecast_from_host( chromecast = pychromecast._get_chromecast_from_host(
mdns, blocking=True, tries=SOCKET_CLIENT_RETRIES) mdns, blocking=True)
except pychromecast.ChromecastConnectionError: except pychromecast.ChromecastConnectionError:
_LOGGER.debug("Can't set up cast with mDNS info %s. " _LOGGER.debug("Can't set up cast with mDNS info %s. "
"Assuming it's not a Chromecast", mdns) "Assuming it's not a Chromecast", mdns)
@ -183,9 +181,8 @@ async def async_setup_platform(hass: HomeAssistantType, config: ConfigType,
else: else:
# Manually add a "normal" Chromecast, we can do that without discovery. # Manually add a "normal" Chromecast, we can do that without discovery.
try: try:
func = functools.partial(pychromecast.Chromecast, *want_host, chromecast = await hass.async_add_job(
tries=SOCKET_CLIENT_RETRIES) pychromecast.Chromecast, *want_host)
chromecast = await hass.async_add_job(func)
except pychromecast.ChromecastConnectionError as err: except pychromecast.ChromecastConnectionError as err:
_LOGGER.warning("Can't set up chromecast on %s: %s", _LOGGER.warning("Can't set up chromecast on %s: %s",
want_host[0], err) want_host[0], err)

View File

@ -31,7 +31,7 @@ from homeassistant.helpers import script, config_validation as cv
from homeassistant.helpers.template import Template from homeassistant.helpers.template import Template
from homeassistant.util.yaml import dump from homeassistant.util.yaml import dump
REQUIREMENTS = ['jsonrpc-async==0.6', 'jsonrpc-websocket==0.5'] REQUIREMENTS = ['jsonrpc-async==0.6', 'jsonrpc-websocket==0.6']
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)

View File

@ -144,7 +144,7 @@ class SQLSensor(Entity):
data = res[self._column_name] data = res[self._column_name]
for key, value in res.items(): for key, value in res.items():
if isinstance(value, decimal.Decimal): if isinstance(value, decimal.Decimal):
value = float(decimal) value = float(value)
self._attributes[key] = value self._attributes[key] = value
except sqlalchemy.exc.SQLAlchemyError as err: except sqlalchemy.exc.SQLAlchemyError as err:
_LOGGER.error("Error executing query %s: %s", self._query, err) _LOGGER.error("Error executing query %s: %s", self._query, err)

View File

@ -19,7 +19,7 @@ from homeassistant.const import (
EVENT_HOMEASSISTANT_STOP, CONF_LIGHTS, CONF_EXCLUDE) EVENT_HOMEASSISTANT_STOP, CONF_LIGHTS, CONF_EXCLUDE)
from homeassistant.helpers.entity import Entity from homeassistant.helpers.entity import Entity
REQUIREMENTS = ['pyvera==0.2.41'] REQUIREMENTS = ['pyvera==0.2.42']
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)

View File

@ -2,7 +2,7 @@
"""Constants used by Home Assistant components.""" """Constants used by Home Assistant components."""
MAJOR_VERSION = 0 MAJOR_VERSION = 0
MINOR_VERSION = 65 MINOR_VERSION = 65
PATCH_VERSION = '2' PATCH_VERSION = '3'
__short_version__ = '{}.{}'.format(MAJOR_VERSION, MINOR_VERSION) __short_version__ = '{}.{}'.format(MAJOR_VERSION, MINOR_VERSION)
__version__ = '{}.{}'.format(__short_version__, PATCH_VERSION) __version__ = '{}.{}'.format(__short_version__, PATCH_VERSION)
REQUIRED_PYTHON_VER = (3, 5, 3) REQUIRED_PYTHON_VER = (3, 5, 3)

View File

@ -398,7 +398,7 @@ https://github.com/wokar/pylgnetcast/archive/v0.2.0.zip#pylgnetcast==0.2.0
# i2csense==0.0.4 # i2csense==0.0.4
# homeassistant.components.light.iglo # homeassistant.components.light.iglo
iglo==1.2.6 iglo==1.2.7
# homeassistant.components.ihc # homeassistant.components.ihc
ihcsdk==2.2.0 ihcsdk==2.2.0
@ -421,7 +421,7 @@ jsonpath==0.75
jsonrpc-async==0.6 jsonrpc-async==0.6
# homeassistant.components.media_player.kodi # homeassistant.components.media_player.kodi
jsonrpc-websocket==0.5 jsonrpc-websocket==0.6
# homeassistant.scripts.keyring # homeassistant.scripts.keyring
keyring==11.0.0 keyring==11.0.0
@ -632,7 +632,7 @@ py-cpuinfo==3.3.0
py-melissa-climate==1.0.6 py-melissa-climate==1.0.6
# homeassistant.components.camera.synology # homeassistant.components.camera.synology
py-synology==0.1.5 py-synology==0.2.0
# homeassistant.components.hdmi_cec # homeassistant.components.hdmi_cec
pyCEC==0.4.13 pyCEC==0.4.13
@ -1021,7 +1021,7 @@ pyunifi==2.13
# pyuserinput==0.1.11 # pyuserinput==0.1.11
# homeassistant.components.vera # homeassistant.components.vera
pyvera==0.2.41 pyvera==0.2.42
# homeassistant.components.media_player.vizio # homeassistant.components.media_player.vizio
pyvizio==0.0.2 pyvizio==0.0.2
@ -1274,7 +1274,7 @@ xbee-helper==0.0.7
xboxapi==0.1.1 xboxapi==0.1.1
# homeassistant.components.knx # homeassistant.components.knx
xknx==0.8.4 xknx==0.8.5
# homeassistant.components.media_player.bluesound # homeassistant.components.media_player.bluesound
# homeassistant.components.sensor.startca # homeassistant.components.sensor.startca

View File

@ -135,7 +135,7 @@ class TestTemplateCover(unittest.TestCase):
entity = self.hass.states.get('cover.test') entity = self.hass.states.get('cover.test')
attrs = dict() attrs = dict()
attrs['position'] = 42 attrs['position'] = 42
self.hass.states.async_set( self.hass.states.set(
entity.entity_id, entity.state, entity.entity_id, entity.state,
attributes=attrs) attributes=attrs)
self.hass.block_till_done() self.hass.block_till_done()
@ -148,7 +148,7 @@ class TestTemplateCover(unittest.TestCase):
self.hass.block_till_done() self.hass.block_till_done()
entity = self.hass.states.get('cover.test') entity = self.hass.states.get('cover.test')
attrs['position'] = 0.0 attrs['position'] = 0.0
self.hass.states.async_set( self.hass.states.set(
entity.entity_id, entity.state, entity.entity_id, entity.state,
attributes=attrs) attributes=attrs)
self.hass.block_till_done() self.hass.block_till_done()

View File

@ -501,3 +501,45 @@ class TestHueLight(unittest.TestCase):
light = self.buildLight(info={}, is_group=True) light = self.buildLight(info={}, is_group=True)
self.assertIsNone(light.unique_id) self.assertIsNone(light.unique_id)
def test_available():
"""Test available property."""
light = hue_light.HueLight(
info={'state': {'reachable': False}},
allow_unreachable=False,
is_group=False,
light_id=None,
bridge=mock.Mock(),
update_lights_cb=None,
allow_in_emulated_hue=False,
)
assert light.available is False
light = hue_light.HueLight(
info={'state': {'reachable': False}},
allow_unreachable=True,
is_group=False,
light_id=None,
bridge=mock.Mock(),
update_lights_cb=None,
allow_in_emulated_hue=False,
)
assert light.available is True
light = hue_light.HueLight(
info={'state': {'reachable': False}},
allow_unreachable=False,
is_group=True,
light_id=None,
bridge=mock.Mock(),
update_lights_cb=None,
allow_in_emulated_hue=False,
)
assert light.available is True

View File

@ -123,7 +123,7 @@ def test_internal_discovery_callback_only_generates_once(hass):
return_value=chromecast) as gen_chromecast: return_value=chromecast) as gen_chromecast:
discover_cast('the-service', chromecast) discover_cast('the-service', chromecast)
mdns = (chromecast.host, chromecast.port, chromecast.uuid, None, None) mdns = (chromecast.host, chromecast.port, chromecast.uuid, None, None)
gen_chromecast.assert_called_once_with(mdns, blocking=True, tries=10) gen_chromecast.assert_called_once_with(mdns, blocking=True)
discover_cast('the-service', chromecast) discover_cast('the-service', chromecast)
gen_chromecast.reset_mock() gen_chromecast.reset_mock()

View File

@ -309,7 +309,7 @@ def test_value_discovery_existing_entity(hass, mock_openzwave):
'current_temperature'] is None 'current_temperature'] is None
def mock_update(self): def mock_update(self):
self.hass.async_add_job(self.async_update_ha_state) self.hass.add_job(self.async_update_ha_state)
with patch.object(zwave.node_entity.ZWaveBaseEntity, with patch.object(zwave.node_entity.ZWaveBaseEntity,
'maybe_schedule_update', new=mock_update): 'maybe_schedule_update', new=mock_update):
@ -356,7 +356,7 @@ def test_power_schemes(hass, mock_openzwave):
'switch.mock_node_mock_value').attributes 'switch.mock_node_mock_value').attributes
def mock_update(self): def mock_update(self):
self.hass.async_add_job(self.async_update_ha_state) self.hass.add_job(self.async_update_ha_state)
with patch.object(zwave.node_entity.ZWaveBaseEntity, with patch.object(zwave.node_entity.ZWaveBaseEntity,
'maybe_schedule_update', new=mock_update): 'maybe_schedule_update', new=mock_update):