Compare commits

..

12 Commits

Author SHA1 Message Date
Paulus Schoutsen fc3235fb6d Merge pull request #4271 from home-assistant/release-0-32-2
Release 0 32 2
2016-11-06 23:40:06 -08:00
David-Leon Pohl d129df93dd Hotfix #4272 (#4273) 2016-11-06 23:34:45 -08:00
Paulus Schoutsen 0af1a96f14 Lint 2016-11-06 23:24:25 -08:00
andyat 272899ec96 Fix setting temperature in Celsius on radiotherm CT50 (#4270) 2016-11-06 23:21:08 -08:00
Paulus Schoutsen 6a92e27e2f Version bump to 0.32.2 2016-11-06 23:12:37 -08:00
Paulus Schoutsen faceb4c1dc Sequential updates for non-async entities 2016-11-06 23:12:20 -08:00
Paulus Schoutsen 6d5f00098a Move Honeywell I/O out of event loop (#4244) 2016-11-06 23:09:31 -08:00
Paulus Schoutsen 08f75f7935 Merge pull request #4235 from home-assistant/release-0-32-1
0.32.1
2016-11-05 17:09:10 -07:00
Paulus Schoutsen af297aa0dc Version bump to 0.32.1 2016-11-05 17:00:06 -07:00
Paulus Schoutsen 20e1b3eae0 Fix radiotherm I/O inside properties (#4227) 2016-11-05 16:59:52 -07:00
Paulus Schoutsen 28861221ae Remove chunked encoding (#4230) 2016-11-05 16:59:52 -07:00
Pascal Vizeli f367c49fb9 Sonos fix for slow update (#4232)
* Sonos fix for slow update

* fix auto update on discovery

* fix unittest
2016-11-05 16:59:52 -07:00
11 changed files with 83 additions and 43 deletions
@@ -101,7 +101,6 @@ class Camera(Entity):
response.content_type = ('multipart/x-mixed-replace; '
'boundary=--jpegboundary')
response.enable_chunked_encoding()
yield from response.prepare(request)
def write(img_bytes):
@@ -75,7 +75,6 @@ class FFmpegCamera(Camera):
response = web.StreamResponse()
response.content_type = 'multipart/x-mixed-replace;boundary=ffserver'
response.enable_chunked_encoding()
yield from response.prepare(request)
-1
View File
@@ -112,7 +112,6 @@ class MjpegCamera(Camera):
response = web.StreamResponse()
response.content_type = stream.headers.get(CONTENT_TYPE_HEADER)
response.enable_chunked_encoding()
yield from response.prepare(request)
@@ -271,7 +271,6 @@ class SynologyCamera(Camera):
response = web.StreamResponse()
response.content_type = stream.headers.get(CONTENT_TYPE_HEADER)
response.enable_chunked_encoding()
yield from response.prepare(request)
@@ -223,7 +223,6 @@ class HoneywellUSThermostat(ClimateDevice):
@property
def current_temperature(self):
"""Return the current temperature."""
self._device.refresh()
return self._device.current_temperature
@property
@@ -274,3 +273,7 @@ class HoneywellUSThermostat(ClimateDevice):
"""Set the system mode (Cool, Heat, etc)."""
if hasattr(self._device, ATTR_SYSTEM_MODE):
self._device.system_mode = operation_mode
def update(self):
"""Update the state."""
self._device.refresh()
+13 -8
View File
@@ -69,6 +69,8 @@ class RadioThermostat(ClimateDevice):
self._current_temperature = None
self._current_operation = STATE_IDLE
self._name = None
self._fmode = None
self._tmode = None
self.hold_temp = hold_temp
self.update()
self._operation_list = [STATE_AUTO, STATE_COOL, STATE_HEAT, STATE_OFF]
@@ -87,8 +89,8 @@ class RadioThermostat(ClimateDevice):
def device_state_attributes(self):
"""Return the device specific state attributes."""
return {
ATTR_FAN: self.device.fmode['human'],
ATTR_MODE: self.device.tmode['human']
ATTR_FAN: self._fmode,
ATTR_MODE: self._tmode,
}
@property
@@ -115,10 +117,13 @@ class RadioThermostat(ClimateDevice):
"""Update the data from the thermostat."""
self._current_temperature = self.device.temp['raw']
self._name = self.device.name['raw']
if self.device.tmode['human'] == 'Cool':
self._fmode = self.device.fmode['human']
self._tmode = self.device.tmode['human']
if self._tmode == 'Cool':
self._target_temperature = self.device.t_cool['raw']
self._current_operation = STATE_COOL
elif self.device.tmode['human'] == 'Heat':
elif self._tmode == 'Heat':
self._target_temperature = self.device.t_heat['raw']
self._current_operation = STATE_HEAT
else:
@@ -130,9 +135,9 @@ class RadioThermostat(ClimateDevice):
if temperature is None:
return
if self._current_operation == STATE_COOL:
self.device.t_cool = temperature
self.device.t_cool = round(temperature * 2.0) / 2.0
elif self._current_operation == STATE_HEAT:
self.device.t_heat = temperature
self.device.t_heat = round(temperature * 2.0) / 2.0
if self.hold_temp:
self.device.hold = 1
else:
@@ -154,6 +159,6 @@ class RadioThermostat(ClimateDevice):
elif operation_mode == STATE_AUTO:
self.device.tmode = 3
elif operation_mode == STATE_COOL:
self.device.t_cool = self._target_temperature
self.device.t_cool = round(self._target_temperature * 2.0) / 2.0
elif operation_mode == STATE_HEAT:
self.device.t_heat = self._target_temperature
self.device.t_heat = round(self._target_temperature * 2.0) / 2.0
+16 -13
View File
@@ -80,7 +80,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
if player.is_visible:
device = SonosDevice(hass, player)
add_devices([device])
add_devices([device], True)
if not DEVICES:
register_services(hass)
DEVICES.append(device)
@@ -106,7 +106,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
return False
DEVICES = [SonosDevice(hass, p) for p in players]
add_devices(DEVICES)
add_devices(DEVICES, True)
register_services(hass)
_LOGGER.info('Added %s Sonos speakers', len(players))
return True
@@ -256,6 +256,7 @@ class SonosDevice(MediaPlayerDevice):
self.hass = hass
self.volume_increment = 5
self._unique_id = player.uid
self._player = player
self._player_volume = None
self._player_volume_muted = None
@@ -278,7 +279,8 @@ class SonosDevice(MediaPlayerDevice):
self._current_track_is_radio_stream = False
self._queue = None
self._last_avtransport_event = None
self.update()
self._is_playing_line_in = None
self._is_playing_tv = None
self.soco_snapshot = Snapshot(self._player)
@property
@@ -286,14 +288,10 @@ class SonosDevice(MediaPlayerDevice):
"""Polling needed."""
return True
def update_sonos(self, now):
"""Update state, called by track_utc_time_change."""
self.update_ha_state(True)
@property
def unique_id(self):
"""Return an unique ID."""
return self._player.uid
return self._unique_id
@property
def name(self):
@@ -354,6 +352,9 @@ class SonosDevice(MediaPlayerDevice):
if is_available:
self._is_playing_tv = self._player.is_playing_tv
self._is_playing_line_in = self._player.is_playing_line_in
track_info = None
if self._last_avtransport_event:
variables = self._last_avtransport_event.variables
@@ -511,10 +512,10 @@ class SonosDevice(MediaPlayerDevice):
# update state of the whole group
# pylint: disable=protected-access
for device in [x for x in DEVICES if x._coordinator == self]:
if device.entity_id:
device.update_ha_state(False)
if device.entity_id is not self.entity_id:
self.hass.add_job(device.async_update_ha_state)
if self._queue is None and self.entity_id:
if self._queue is None:
self._subscribe_to_player_events()
else:
self._player_volume = None
@@ -534,6 +535,8 @@ class SonosDevice(MediaPlayerDevice):
self._support_previous_track = False
self._support_next_track = False
self._support_pause = False
self._is_playing_tv = False
self._is_playing_line_in = False
self._last_avtransport_event = None
@@ -713,9 +716,9 @@ class SonosDevice(MediaPlayerDevice):
@property
def source(self):
"""Name of the current input source."""
if self._player.is_playing_line_in:
if self._is_playing_line_in:
return SUPPORT_SOURCE_LINEIN
if self._player.is_playing_tv:
if self._is_playing_tv:
return SUPPORT_SOURCE_TV
return None
+4 -2
View File
@@ -37,8 +37,10 @@ SWITCHES_SCHEMA = vol.Schema({
vol.Required(CONF_ON_CODE): COMMAND_SCHEMA,
vol.Required(CONF_OFF_CODE): COMMAND_SCHEMA,
vol.Optional(CONF_NAME): cv.string,
vol.Optional(CONF_OFF_CODE_RECIEVE): COMMAND_SCHEMA,
vol.Optional(CONF_ON_CODE_RECIEVE): COMMAND_SCHEMA,
vol.Optional(CONF_OFF_CODE_RECIEVE, default=[]): vol.All(cv.ensure_list,
[COMMAND_SCHEMA]),
vol.Optional(CONF_ON_CODE_RECIEVE, default=[]): vol.All(cv.ensure_list,
[COMMAND_SCHEMA])
})
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
+1 -1
View File
@@ -2,7 +2,7 @@
"""Constants used by Home Assistant components."""
MAJOR_VERSION = 0
MINOR_VERSION = 32
PATCH_VERSION = '0'
PATCH_VERSION = '2'
__short_version__ = '{}.{}'.format(MAJOR_VERSION, MINOR_VERSION)
__version__ = '{}.{}'.format(__short_version__, PATCH_VERSION)
REQUIRED_PYTHON_VER = (3, 4, 2)
+30 -6
View File
@@ -279,6 +279,7 @@ class EntityPlatform(object):
self.entity_namespace = entity_namespace
self.platform_entities = []
self._async_unsub_polling = None
self._process_updates = False
def add_entities(self, new_entities, update_before_add=False):
"""Add entities for a single platform."""
@@ -335,14 +336,37 @@ class EntityPlatform(object):
self._async_unsub_polling()
self._async_unsub_polling = None
@callback
@asyncio.coroutine
def _update_entity_states(self, now):
"""Update the states of all the polling entities.
To protect from flooding the executor, we will update async entities
in parallel and other entities sequential.
This method must be run in the event loop.
"""
for entity in self.platform_entities:
if entity.should_poll:
self.component.hass.loop.create_task(
entity.async_update_ha_state(True)
)
if self._process_updates:
return
self._process_updates = True
try:
tasks = []
to_update = []
for entity in self.platform_entities:
if not entity.should_poll:
continue
update_coro = entity.async_update_ha_state(True)
if hasattr(entity, 'async_update'):
tasks.append(update_coro)
else:
to_update.append(update_coro)
for update_coro in to_update:
yield from update_coro
if tasks:
yield from asyncio.wait(tasks, loop=self.component.hass.loop)
finally:
self._process_updates = False
+15 -8
View File
@@ -92,6 +92,13 @@ class SoCoMock():
return "RINCON_XXXXXXXXXXXXXXXXX"
def fake_add_device(devices, update_befor_add=False):
"""Fake add device / update."""
if update_befor_add:
for speaker in devices:
speaker.update()
class TestSonosMediaPlayer(unittest.TestCase):
"""Test the media_player module."""
@@ -117,7 +124,7 @@ class TestSonosMediaPlayer(unittest.TestCase):
@mock.patch('socket.create_connection', side_effect=socket.error())
def test_ensure_setup_discovery(self, *args):
"""Test a single device using the autodiscovery provided by HASS."""
sonos.setup_platform(self.hass, {}, mock.MagicMock(), '192.0.2.1')
sonos.setup_platform(self.hass, {}, fake_add_device, '192.0.2.1')
# Ensure registration took place (#2558)
self.assertEqual(len(sonos.DEVICES), 1)
@@ -129,7 +136,7 @@ class TestSonosMediaPlayer(unittest.TestCase):
"""Test a single address config'd by the HASS config file."""
sonos.setup_platform(self.hass,
{'hosts': '192.0.2.1'},
mock.MagicMock())
fake_add_device)
# Ensure registration took place (#2558)
self.assertEqual(len(sonos.DEVICES), 1)
@@ -140,7 +147,7 @@ class TestSonosMediaPlayer(unittest.TestCase):
@mock.patch('socket.create_connection', side_effect=socket.error())
def test_ensure_setup_sonos_discovery(self, *args):
"""Test a single device using the autodiscovery provided by Sonos."""
sonos.setup_platform(self.hass, {}, mock.MagicMock())
sonos.setup_platform(self.hass, {}, fake_add_device)
self.assertEqual(len(sonos.DEVICES), 1)
self.assertEqual(sonos.DEVICES[0].name, 'Kitchen')
@@ -149,7 +156,7 @@ class TestSonosMediaPlayer(unittest.TestCase):
@mock.patch.object(SoCoMock, 'partymode')
def test_sonos_group_players(self, partymodeMock, *args):
"""Ensuring soco methods called for sonos_group_players service."""
sonos.setup_platform(self.hass, {}, mock.MagicMock(), '192.0.2.1')
sonos.setup_platform(self.hass, {}, fake_add_device, '192.0.2.1')
device = sonos.DEVICES[-1]
partymodeMock.return_value = True
device.group_players()
@@ -161,7 +168,7 @@ class TestSonosMediaPlayer(unittest.TestCase):
@mock.patch.object(SoCoMock, 'unjoin')
def test_sonos_unjoin(self, unjoinMock, *args):
"""Ensuring soco methods called for sonos_unjoin service."""
sonos.setup_platform(self.hass, {}, mock.MagicMock(), '192.0.2.1')
sonos.setup_platform(self.hass, {}, fake_add_device, '192.0.2.1')
device = sonos.DEVICES[-1]
unjoinMock.return_value = True
device.unjoin()
@@ -173,7 +180,7 @@ class TestSonosMediaPlayer(unittest.TestCase):
@mock.patch.object(SoCoMock, 'set_sleep_timer')
def test_sonos_set_sleep_timer(self, set_sleep_timerMock, *args):
"""Ensuring soco methods called for sonos_set_sleep_timer service."""
sonos.setup_platform(self.hass, {}, mock.MagicMock(), '192.0.2.1')
sonos.setup_platform(self.hass, {}, fake_add_device, '192.0.2.1')
device = sonos.DEVICES[-1]
device.set_sleep_timer(30)
set_sleep_timerMock.assert_called_once_with(30)
@@ -193,7 +200,7 @@ class TestSonosMediaPlayer(unittest.TestCase):
@mock.patch.object(soco.snapshot.Snapshot, 'snapshot')
def test_sonos_snapshot(self, snapshotMock, *args):
"""Ensuring soco methods called for sonos_snapshot service."""
sonos.setup_platform(self.hass, {}, mock.MagicMock(), '192.0.2.1')
sonos.setup_platform(self.hass, {}, fake_add_device, '192.0.2.1')
device = sonos.DEVICES[-1]
snapshotMock.return_value = True
device.snapshot()
@@ -205,7 +212,7 @@ class TestSonosMediaPlayer(unittest.TestCase):
@mock.patch.object(soco.snapshot.Snapshot, 'restore')
def test_sonos_restore(self, restoreMock, *args):
"""Ensuring soco methods called for sonos_restor service."""
sonos.setup_platform(self.hass, {}, mock.MagicMock(), '192.0.2.1')
sonos.setup_platform(self.hass, {}, fake_add_device, '192.0.2.1')
device = sonos.DEVICES[-1]
restoreMock.return_value = True
device.restore()