Add channel changing support to SamsungTV component (#14451)

Add channel changing support to SamsungTV component
This commit is contained in:
Matt LeBrun 2018-06-26 10:22:10 -04:00 committed by Martin Hjelmare
parent c79c94550f
commit 0094fd5c34
2 changed files with 85 additions and 4 deletions

View File

@ -4,6 +4,7 @@ Support for interface with an Samsung TV.
For more details about this platform, please refer to the documentation at For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/media_player.samsungtv/ https://home-assistant.io/components/media_player.samsungtv/
""" """
import asyncio
import logging import logging
import socket import socket
from datetime import timedelta from datetime import timedelta
@ -15,8 +16,9 @@ import voluptuous as vol
from homeassistant.components.media_player import ( from homeassistant.components.media_player import (
SUPPORT_NEXT_TRACK, SUPPORT_PAUSE, SUPPORT_PREVIOUS_TRACK, SUPPORT_NEXT_TRACK, SUPPORT_PAUSE, SUPPORT_PREVIOUS_TRACK,
SUPPORT_TURN_OFF, SUPPORT_VOLUME_MUTE, SUPPORT_VOLUME_STEP, SUPPORT_TURN_OFF, SUPPORT_TURN_ON, SUPPORT_PLAY,
SUPPORT_PLAY, MediaPlayerDevice, PLATFORM_SCHEMA, SUPPORT_TURN_ON) SUPPORT_VOLUME_MUTE, SUPPORT_VOLUME_STEP, SUPPORT_PLAY_MEDIA,
MediaPlayerDevice, PLATFORM_SCHEMA, MEDIA_TYPE_CHANNEL)
from homeassistant.const import ( from homeassistant.const import (
CONF_HOST, CONF_NAME, STATE_OFF, STATE_ON, STATE_UNKNOWN, CONF_PORT, CONF_HOST, CONF_NAME, STATE_OFF, STATE_ON, STATE_UNKNOWN, CONF_PORT,
CONF_MAC) CONF_MAC)
@ -32,12 +34,13 @@ CONF_TIMEOUT = 'timeout'
DEFAULT_NAME = 'Samsung TV Remote' DEFAULT_NAME = 'Samsung TV Remote'
DEFAULT_PORT = 55000 DEFAULT_PORT = 55000
DEFAULT_TIMEOUT = 0 DEFAULT_TIMEOUT = 0
KEY_PRESS_TIMEOUT = 1.2
KNOWN_DEVICES_KEY = 'samsungtv_known_devices' KNOWN_DEVICES_KEY = 'samsungtv_known_devices'
SUPPORT_SAMSUNGTV = SUPPORT_PAUSE | SUPPORT_VOLUME_STEP | \ SUPPORT_SAMSUNGTV = SUPPORT_PAUSE | SUPPORT_VOLUME_STEP | \
SUPPORT_VOLUME_MUTE | SUPPORT_PREVIOUS_TRACK | \ SUPPORT_VOLUME_MUTE | SUPPORT_PREVIOUS_TRACK | \
SUPPORT_NEXT_TRACK | SUPPORT_TURN_OFF | SUPPORT_PLAY SUPPORT_NEXT_TRACK | SUPPORT_TURN_OFF | SUPPORT_PLAY | SUPPORT_PLAY_MEDIA
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Required(CONF_HOST): cv.string, vol.Required(CONF_HOST): cv.string,
@ -256,6 +259,23 @@ class SamsungTVDevice(MediaPlayerDevice):
"""Send the previous track command.""" """Send the previous track command."""
self.send_key('KEY_REWIND') self.send_key('KEY_REWIND')
async def async_play_media(self, media_type, media_id, **kwargs):
"""Support changing a channel."""
if media_type != MEDIA_TYPE_CHANNEL:
_LOGGER.error('Unsupported media type')
return
# media_id should only be a channel number
try:
cv.positive_int(media_id)
except vol.Invalid:
_LOGGER.error('Media ID must be positive integer')
return
for digit in media_id:
await self.hass.async_add_job(self.send_key, 'KEY_' + digit)
await asyncio.sleep(KEY_PRESS_TIMEOUT, self.hass.loop)
def turn_on(self): def turn_on(self):
"""Turn the media player on.""" """Turn the media player on."""
if self._mac: if self._mac:

View File

@ -1,11 +1,16 @@
"""Tests for samsungtv Components.""" """Tests for samsungtv Components."""
import asyncio
import unittest import unittest
from unittest.mock import call, patch, MagicMock
from subprocess import CalledProcessError from subprocess import CalledProcessError
from asynctest import mock from asynctest import mock
import pytest
import tests.common import tests.common
from homeassistant.components.media_player import SUPPORT_TURN_ON from homeassistant.components.media_player import SUPPORT_TURN_ON, \
MEDIA_TYPE_CHANNEL, MEDIA_TYPE_URL
from homeassistant.components.media_player.samsungtv import setup_platform, \ from homeassistant.components.media_player.samsungtv import setup_platform, \
CONF_TIMEOUT, SamsungTVDevice, SUPPORT_SAMSUNGTV CONF_TIMEOUT, SamsungTVDevice, SUPPORT_SAMSUNGTV
from homeassistant.const import CONF_HOST, CONF_NAME, CONF_PORT, STATE_ON, \ from homeassistant.const import CONF_HOST, CONF_NAME, CONF_PORT, STATE_ON, \
@ -301,3 +306,59 @@ class TestSamsungTv(unittest.TestCase):
self.device._mac = "fake" self.device._mac = "fake"
self.device.turn_on() self.device.turn_on()
self.device._wol.send_magic_packet.assert_called_once_with("fake") self.device._wol.send_magic_packet.assert_called_once_with("fake")
@pytest.fixture
def samsung_mock():
"""Mock samsungctl."""
with patch.dict('sys.modules', {
'samsungctl': MagicMock(),
}):
yield
async def test_play_media(hass, samsung_mock):
"""Test for play_media."""
asyncio_sleep = asyncio.sleep
sleeps = []
async def sleep(duration, loop):
sleeps.append(duration)
await asyncio_sleep(0, loop=loop)
with patch('asyncio.sleep', new=sleep):
device = SamsungTVDevice(**WORKING_CONFIG)
device.hass = hass
device.send_key = mock.Mock()
await device.async_play_media(MEDIA_TYPE_CHANNEL, "576")
exp = [call("KEY_5"), call("KEY_7"), call("KEY_6")]
assert device.send_key.call_args_list == exp
assert len(sleeps) == 3
async def test_play_media_invalid_type(hass, samsung_mock):
"""Test for play_media with invalid media type."""
url = "https://example.com"
device = SamsungTVDevice(**WORKING_CONFIG)
device.send_key = mock.Mock()
await device.async_play_media(MEDIA_TYPE_URL, url)
assert device.send_key.call_count == 0
async def test_play_media_channel_as_string(hass, samsung_mock):
"""Test for play_media with invalid channel as string."""
url = "https://example.com"
device = SamsungTVDevice(**WORKING_CONFIG)
device.send_key = mock.Mock()
await device.async_play_media(MEDIA_TYPE_CHANNEL, url)
assert device.send_key.call_count == 0
async def test_play_media_channel_as_non_positive(hass, samsung_mock):
"""Test for play_media with invalid channel as non positive integer."""
device = SamsungTVDevice(**WORKING_CONFIG)
device.send_key = mock.Mock()
await device.async_play_media(MEDIA_TYPE_CHANNEL, "-4")
assert device.send_key.call_count == 0