add turn on action (dry without testing)

This commit is contained in:
escoand
2020-01-03 09:49:38 +01:00
parent d5a7375da8
commit 5a77dcdd3d
9 changed files with 72 additions and 139 deletions

View File

@@ -1,17 +1,10 @@
"""The Samsung TV integration."""
import voluptuous as vol
from wakeonlan import BROADCAST_IP
from homeassistant.const import (
CONF_BROADCAST_ADDRESS,
CONF_HOST,
CONF_MAC,
CONF_NAME,
CONF_PORT,
)
from homeassistant.const import CONF_HOST, CONF_NAME, CONF_PORT
import homeassistant.helpers.config_validation as cv
from .const import DEFAULT_NAME, DOMAIN
from .const import CONF_ON_ACTION, DEFAULT_NAME, DOMAIN
CONFIG_SCHEMA = vol.Schema(
{
@@ -22,10 +15,7 @@ CONFIG_SCHEMA = vol.Schema(
vol.Required(CONF_HOST): cv.string,
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
vol.Optional(CONF_PORT): cv.port,
vol.Optional(CONF_MAC): cv.string,
vol.Optional(
CONF_BROADCAST_ADDRESS, default=BROADCAST_IP
): cv.string,
vol.Optional(CONF_ON_ACTION): cv.SCRIPT_SCHEMA,
}
)
]

View File

@@ -14,16 +14,21 @@ from homeassistant.components.ssdp import (
ATTR_UPNP_UDN,
)
from homeassistant.const import (
CONF_BROADCAST_ADDRESS,
CONF_HOST,
CONF_ID,
CONF_IP_ADDRESS,
CONF_MAC,
CONF_NAME,
CONF_PORT,
)
from .const import CONF_MANUFACTURER, CONF_MODEL, DOMAIN, LOGGER, METHODS
from .const import (
CONF_MANUFACTURER,
CONF_MODEL,
CONF_ON_ACTION,
DOMAIN,
LOGGER,
METHODS,
)
DATA_SCHEMA = vol.Schema({vol.Required(CONF_HOST): str, vol.Required(CONF_NAME): str})
@@ -90,13 +95,12 @@ class SamsungTVConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
def __init__(self):
"""Initialize flow."""
self._broadcast = None
self._host = None
self._ip = None
self._mac = None
self._manufacturer = None
self._model = None
self._name = None
self._on_script = None
self._port = None
self._title = None
self._uuid = None
@@ -105,14 +109,13 @@ class SamsungTVConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
return self.async_create_entry(
title=self._title,
data={
CONF_BROADCAST_ADDRESS: self._broadcast,
CONF_HOST: self._host,
CONF_ID: self._uuid,
CONF_IP_ADDRESS: self._ip,
CONF_MAC: self._mac,
CONF_MANUFACTURER: self._manufacturer,
CONF_MODEL: self._model,
CONF_NAME: self._name,
CONF_ON_ACTION: self._on_script,
CONF_PORT: self._port,
},
)
@@ -134,10 +137,9 @@ class SamsungTVConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
if _is_already_configured(self.hass, ip_address):
return self.async_abort(reason="already_configured")
self._broadcast = user_input.get(CONF_BROADCAST_ADDRESS)
self._host = user_input.get(CONF_HOST)
self._ip = self.context[CONF_IP_ADDRESS] = ip_address
self._mac = user_input.get(CONF_MAC)
self._on_script = user_input.get(CONF_ON_ACTION)
self._port = user_input.get(CONF_PORT)
self._title = user_input.get(CONF_NAME)

View File

@@ -8,5 +8,6 @@ DEFAULT_NAME = "Samsung TV Remote"
CONF_MANUFACTURER = "manufacturer"
CONF_MODEL = "model"
CONF_ON_ACTION = "turn_on_action"
METHODS = ("websocket", "legacy")

View File

@@ -3,8 +3,7 @@
"name": "Samsung TV",
"documentation": "https://www.home-assistant.io/integrations/samsungtv",
"requirements": [
"samsungctl[websocket]==0.7.1",
"wakeonlan==1.1.6"
"samsungctl[websocket]==0.7.1"
],
"ssdp": [
{

View File

@@ -4,7 +4,6 @@ from datetime import timedelta
from samsungctl import Remote as SamsungRemote, exceptions as samsung_exceptions
import voluptuous as vol
import wakeonlan
from websocket import WebSocketException
from homeassistant.components.media_player import DEVICE_CLASS_TV, MediaPlayerDevice
@@ -21,19 +20,19 @@ from homeassistant.components.media_player.const import (
SUPPORT_VOLUME_MUTE,
SUPPORT_VOLUME_STEP,
)
from homeassistant.const import (
CONF_BROADCAST_ADDRESS,
CONF_HOST,
CONF_ID,
CONF_MAC,
CONF_PORT,
STATE_OFF,
STATE_ON,
)
from homeassistant.const import CONF_HOST, CONF_ID, CONF_PORT, STATE_OFF, STATE_ON
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.script import Script
from homeassistant.util import dt as dt_util
from .const import CONF_MANUFACTURER, CONF_MODEL, DOMAIN, LOGGER, METHODS
from .const import (
CONF_MANUFACTURER,
CONF_MODEL,
CONF_ON_ACTION,
DOMAIN,
LOGGER,
METHODS,
)
KEY_PRESS_TIMEOUT = 1.2
SOURCES = {"TV": "KEY_TV", "HDMI": "KEY_HDMI"}
@@ -61,20 +60,16 @@ async def async_setup_platform(
async def async_setup_entry(hass, config_entry, async_add_entities):
"""Set up the Samsung TV from a config entry."""
host = config_entry.data[CONF_HOST]
mac = config_entry.data.get(CONF_MAC)
broadcast = config_entry.data.get(CONF_BROADCAST_ADDRESS) or wakeonlan.BROADCAST_IP
manufacturer = config_entry.data.get(CONF_MANUFACTURER)
model = config_entry.data.get(CONF_MODEL)
name = config_entry.title
port = config_entry.data.get(CONF_PORT)
uuid = config_entry.data.get(CONF_ID)
turn_on_action = config_entry.data.get(CONF_ON_ACTION)
on_script = Script(hass, turn_on_action) if turn_on_action else None
async_add_entities(
[
SamsungTVDevice(
host, port, name, mac, broadcast, uuid, manufacturer, model
)
]
[SamsungTVDevice(host, port, name, uuid, manufacturer, model, on_script)]
)
@@ -82,24 +77,15 @@ class SamsungTVDevice(MediaPlayerDevice):
"""Representation of a Samsung TV."""
def __init__(
self,
host,
port,
name,
mac,
broadcast,
uuid,
manufacturer=None,
model=None,
self, host, port, name, uuid, manufacturer=None, model=None, on_script=None,
):
"""Initialize the Samsung device."""
self._name = name
self._mac = mac
self._broadcast = broadcast
self._uuid = uuid
self._manufacturer = manufacturer
self._model = model
self._on_script = on_script
# Assume that the TV is not muted
self._muted = False
# Assume that the TV is in Play mode
@@ -250,7 +236,7 @@ class SamsungTVDevice(MediaPlayerDevice):
@property
def supported_features(self):
"""Flag media player features that are supported."""
if self._mac:
if self._on_script:
return SUPPORT_SAMSUNGTV | SUPPORT_TURN_ON
return SUPPORT_SAMSUNGTV
@@ -329,10 +315,10 @@ class SamsungTVDevice(MediaPlayerDevice):
await asyncio.sleep(KEY_PRESS_TIMEOUT, self.hass.loop)
await self.hass.async_add_job(self.send_key, "KEY_ENTER")
def turn_on(self):
async def async_turn_on(self):
"""Turn the media player on."""
if self._mac:
wakeonlan.send_magic_packet(self._mac, ip_address=self._broadcast)
if self._on_script:
await self.hass.async_add_job(self._on_script.async_run())
else:
self.send_key("KEY_POWERON")

View File

@@ -2016,7 +2016,6 @@ vtjp==0.1.14
vultr==0.1.2
# homeassistant.components.panasonic_viera
# homeassistant.components.samsungtv
# homeassistant.components.wake_on_lan
wakeonlan==1.1.6

View File

@@ -629,7 +629,6 @@ vsure==1.5.4
vultr==0.1.2
# homeassistant.components.panasonic_viera
# homeassistant.components.samsungtv
# homeassistant.components.wake_on_lan
wakeonlan==1.1.6

View File

@@ -5,14 +5,15 @@ import pytest
from homeassistant.components import samsungtv
from homeassistant.components.media_player.const import DOMAIN, SUPPORT_TURN_ON
from homeassistant.components.samsungtv.const import DOMAIN as SAMSUNGTV_DOMAIN
from homeassistant.components.samsungtv.const import (
CONF_ON_ACTION,
DOMAIN as SAMSUNGTV_DOMAIN,
)
from homeassistant.components.samsungtv.media_player import SUPPORT_SAMSUNGTV
from homeassistant.const import (
ATTR_ENTITY_ID,
ATTR_SUPPORTED_FEATURES,
CONF_BROADCAST_ADDRESS,
CONF_HOST,
CONF_MAC,
CONF_NAME,
CONF_PORT,
SERVICE_VOLUME_UP,
@@ -22,11 +23,10 @@ ENTITY_ID = f"{DOMAIN}.fake_name"
MOCK_CONFIG = {
SAMSUNGTV_DOMAIN: [
{
CONF_BROADCAST_ADDRESS: "fake_broadcast",
CONF_HOST: "fake_host",
CONF_MAC: "fake_mac",
CONF_NAME: "fake_name",
CONF_PORT: 1234,
CONF_ON_ACTION: None,
}
]
}
@@ -56,7 +56,7 @@ async def test_setup(hass, remote):
await hass.async_block_till_done()
state = hass.states.get(ENTITY_ID)
# test name and mac
# test name and turn_on
assert state
assert state.name == "fake_name"
assert (

View File

@@ -7,7 +7,6 @@ from unittest.mock import call, patch
from asynctest import mock
import pytest
from samsungctl import exceptions
import wakeonlan
from websocket import WebSocketException
from homeassistant.components.media_player import DEVICE_CLASS_TV
@@ -23,16 +22,17 @@ from homeassistant.components.media_player.const import (
SERVICE_SELECT_SOURCE,
SUPPORT_TURN_ON,
)
from homeassistant.components.samsungtv.const import DOMAIN as SAMSUNGTV_DOMAIN
from homeassistant.components.samsungtv.const import (
CONF_ON_ACTION,
DOMAIN as SAMSUNGTV_DOMAIN,
)
from homeassistant.components.samsungtv.media_player import SUPPORT_SAMSUNGTV
from homeassistant.const import (
ATTR_DEVICE_CLASS,
ATTR_ENTITY_ID,
ATTR_FRIENDLY_NAME,
ATTR_SUPPORTED_FEATURES,
CONF_BROADCAST_ADDRESS,
CONF_HOST,
CONF_MAC,
CONF_NAME,
CONF_PORT,
SERVICE_MEDIA_NEXT_TRACK,
@@ -60,32 +60,15 @@ MOCK_CONFIG = {
CONF_HOST: "fake",
CONF_NAME: "fake",
CONF_PORT: 8001,
CONF_MAC: "38:f9:d3:82:b4:f1",
CONF_ON_ACTION: [{"delay": "00:00:01"}],
}
]
}
ENTITY_ID_BROADCAST = f"{DOMAIN}.fake_broadcast"
MOCK_CONFIG_BROADCAST = {
ENTITY_ID_NOTURNON = f"{DOMAIN}.fake_noturnon"
MOCK_CONFIG_NOTURNON = {
SAMSUNGTV_DOMAIN: [
{
CONF_HOST: "fake_broadcast",
CONF_NAME: "fake_broadcast",
CONF_PORT: 8001,
CONF_MAC: "38:f9:d3:82:b4:f1",
CONF_BROADCAST_ADDRESS: "192.168.5.255",
}
]
}
ENTITY_ID_NOMAC = f"{DOMAIN}.fake_nomac"
MOCK_CONFIG_NOMAC = {
SAMSUNGTV_DOMAIN: [
{
CONF_HOST: "fake_nomac",
CONF_NAME: "fake_nomac",
CONF_PORT: 55000,
}
{CONF_HOST: "fake_noturnon", CONF_NAME: "fake_noturnon", CONF_PORT: 55000}
]
}
@@ -151,16 +134,6 @@ def remote_fixture():
yield remote
@pytest.fixture(name="wakeonlan")
def wakeonlan_fixture():
"""Patch the wakeonlan Remote."""
with patch(
"homeassistant.components.samsungtv.media_player.wakeonlan"
) as wakeonlan_module:
wakeonlan_module.BROADCAST_IP = wakeonlan.BROADCAST_IP
yield wakeonlan_module
@pytest.fixture
def mock_now():
"""Fixture for dtutil.now."""
@@ -173,7 +146,7 @@ async def setup_samsungtv(hass, config):
await hass.async_block_till_done()
async def test_setup_with_mac(hass, remote):
async def test_setup_with_turnon(hass, remote):
"""Test setup of platform."""
await setup_samsungtv(hass, MOCK_CONFIG)
assert hass.states.get(ENTITY_ID)
@@ -192,10 +165,10 @@ async def test_setup_duplicate(hass, remote, caplog):
assert len(hass.states.async_all()) == 1
async def test_setup_without_mac(hass, remote):
async def test_setup_without_turnon(hass, remote):
"""Test setup of platform."""
await setup_samsungtv(hass, MOCK_CONFIG_NOMAC)
assert hass.states.get(ENTITY_ID_NOMAC)
await setup_samsungtv(hass, MOCK_CONFIG_NOTURNON)
assert hass.states.get(ENTITY_ID_NOTURNON)
async def test_update_on(hass, remote, mock_now):
@@ -225,7 +198,7 @@ async def test_update_off(hass, remote, mock_now):
assert state.state == STATE_OFF
async def test_send_key(hass, remote, wakeonlan):
async def test_send_key(hass, remote):
"""Test for send key."""
await setup_samsungtv(hass, MOCK_CONFIG)
assert await hass.services.async_call(
@@ -394,7 +367,7 @@ async def test_name(hass, remote):
assert state.attributes[ATTR_FRIENDLY_NAME] == "fake"
async def test_state_with_mac(hass, remote, wakeonlan):
async def test_state_with_turnon(hass, remote):
"""Test for state property."""
await setup_samsungtv(hass, MOCK_CONFIG)
assert await hass.services.async_call(
@@ -409,22 +382,22 @@ async def test_state_with_mac(hass, remote, wakeonlan):
assert state.state == STATE_OFF
async def test_state_without_mac(hass, remote):
async def test_state_without_turnon(hass, remote):
"""Test for state property."""
await setup_samsungtv(hass, MOCK_CONFIG_NOMAC)
await setup_samsungtv(hass, MOCK_CONFIG_NOTURNON)
assert await hass.services.async_call(
DOMAIN, SERVICE_VOLUME_UP, {ATTR_ENTITY_ID: ENTITY_ID_NOMAC}, True
DOMAIN, SERVICE_VOLUME_UP, {ATTR_ENTITY_ID: ENTITY_ID_NOTURNON}, True
)
state = hass.states.get(ENTITY_ID_NOMAC)
state = hass.states.get(ENTITY_ID_NOTURNON)
assert state.state == STATE_ON
assert await hass.services.async_call(
DOMAIN, SERVICE_TURN_OFF, {ATTR_ENTITY_ID: ENTITY_ID_NOMAC}, True
DOMAIN, SERVICE_TURN_OFF, {ATTR_ENTITY_ID: ENTITY_ID_NOTURNON}, True
)
state = hass.states.get(ENTITY_ID_NOMAC)
state = hass.states.get(ENTITY_ID_NOTURNON)
assert state.state == STATE_OFF
async def test_supported_features_with_mac(hass, remote):
async def test_supported_features_with_turnon(hass, remote):
"""Test for supported_features property."""
await setup_samsungtv(hass, MOCK_CONFIG)
state = hass.states.get(ENTITY_ID)
@@ -433,10 +406,10 @@ async def test_supported_features_with_mac(hass, remote):
)
async def test_supported_features_without_mac(hass, remote):
async def test_supported_features_without_turnon(hass, remote):
"""Test for supported_features property."""
await setup_samsungtv(hass, MOCK_CONFIG_NOMAC)
state = hass.states.get(ENTITY_ID_NOMAC)
await setup_samsungtv(hass, MOCK_CONFIG_NOTURNON)
state = hass.states.get(ENTITY_ID_NOTURNON)
assert state.attributes[ATTR_SUPPORTED_FEATURES] == SUPPORT_SAMSUNGTV
@@ -460,9 +433,9 @@ async def test_turn_off_websocket(hass, remote):
async def test_turn_off_legacy(hass, remote):
"""Test for turn_off."""
await setup_samsungtv(hass, MOCK_CONFIG_NOMAC)
await setup_samsungtv(hass, MOCK_CONFIG_NOTURNON)
assert await hass.services.async_call(
DOMAIN, SERVICE_TURN_OFF, {ATTR_ENTITY_ID: ENTITY_ID_NOMAC}, True
DOMAIN, SERVICE_TURN_OFF, {ATTR_ENTITY_ID: ENTITY_ID_NOTURNON}, True
)
# key called
assert remote.control.call_count == 1
@@ -560,37 +533,21 @@ async def test_media_previous_track(hass, remote):
assert remote.control.call_args_list == [call("KEY_CHDOWN"), call("KEY")]
async def test_turn_on_with_mac(hass, remote, wakeonlan):
async def test_turn_on_with_turnon(hass, remote):
"""Test turn on."""
await setup_samsungtv(hass, MOCK_CONFIG)
assert await hass.services.async_call(
DOMAIN, SERVICE_TURN_ON, {ATTR_ENTITY_ID: ENTITY_ID}, True
)
# key and update called
assert wakeonlan.send_magic_packet.call_count == 1
assert wakeonlan.send_magic_packet.call_args_list == [
call("38:f9:d3:82:b4:f1", ip_address="255.255.255.255")
]
assert False # TODO
async def test_turn_on_with_mac_and_broadcast(hass, remote, wakeonlan):
async def test_turn_on_without_turnon(hass, remote):
"""Test turn on."""
await setup_samsungtv(hass, MOCK_CONFIG_BROADCAST)
await setup_samsungtv(hass, MOCK_CONFIG_NOTURNON)
assert await hass.services.async_call(
DOMAIN, SERVICE_TURN_ON, {ATTR_ENTITY_ID: ENTITY_ID_BROADCAST}, True
)
# key and update called
assert wakeonlan.send_magic_packet.call_count == 1
assert wakeonlan.send_magic_packet.call_args_list == [
call("38:f9:d3:82:b4:f1", ip_address="192.168.5.255")
]
async def test_turn_on_without_mac(hass, remote):
"""Test turn on."""
await setup_samsungtv(hass, MOCK_CONFIG_NOMAC)
assert await hass.services.async_call(
DOMAIN, SERVICE_TURN_ON, {ATTR_ENTITY_ID: ENTITY_ID_NOMAC}, True
DOMAIN, SERVICE_TURN_ON, {ATTR_ENTITY_ID: ENTITY_ID_NOTURNON}, True
)
# nothing called as not supported feature
assert remote.control.call_count == 0