Compare commits
12 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| fc3235fb6d | |||
| d129df93dd | |||
| 0af1a96f14 | |||
| 272899ec96 | |||
| 6a92e27e2f | |||
| faceb4c1dc | |||
| 6d5f00098a | |||
| 08f75f7935 | |||
| af297aa0dc | |||
| 20e1b3eae0 | |||
| 28861221ae | |||
| f367c49fb9 |
@@ -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)
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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({
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user