It is possible to set the HDMI input over UPnP. I don’t know if newer Samsung TVs has still the API, but on older TVs (2012, 2013) it was possible. The “MainTVAgent2” UPnP-service has the method “SetMainTVSource”. Also there are several other methods like “SetMainTVChannel”, “SetVolume”, “Play”, “Pause”, “Stop”, etc. I used gupnp-tools on Ubuntu to discover the services and play around with them.
I have Samsung 2011 ue40d6100sw is determined by HA but constantly shows that is turned off.
media_player: - platform: samsungtv host: 192.168.13.99 mac: xx:xx:xx:xx:xx:xx port: 8001
Who can tell me what the problem is?
Thank you so much, my friend. Temporarily question decided to =)
How/where do I implement this code for KEY_“XX” sends?
I’m not sure where to add or find the custom_components/media_player/ folder.
Any insights would be appreciated!
EDIT
I think I’ve worked it out. The folders need to be created in /config.
I get “ms.channel.unauthorized” when connecting to Samsung TV UE55NU6035 and I haven’t been able to figure it out.
Here are the logs when pressing the on/off button in the UI:
2019-03-07 16:38:59 ERROR (MainThread) [homeassistant.components.websocket_api.http.connection.4552020656] {'event': 'ms.channel.unauthorized'}
Traceback (most recent call last):
File "/usr/local/lib/python3.7/site-packages/homeassistant/components/websocket_api/commands.py", line 148, in handle_call_service
connection.context(msg))
File "/usr/local/lib/python3.7/site-packages/homeassistant/core.py", line 1133, in async_call
self._execute_service(handler, service_call))
File "/usr/local/lib/python3.7/site-packages/homeassistant/core.py", line 1155, in _execute_service
await handler.func(service_call)
File "/usr/local/lib/python3.7/site-packages/homeassistant/helpers/entity_component.py", line 188, in handle_service
self._platforms.values(), func, call, service_name
File "/usr/local/lib/python3.7/site-packages/homeassistant/helpers/service.py", line 278, in entity_service_call
future.result() # pop exception if have
File "/usr/local/lib/python3.7/site-packages/homeassistant/helpers/service.py", line 292, in _handle_service_platform_call
await getattr(entity, func)(**data)
File "/usr/local/Cellar/python/3.7.2_1/Frameworks/Python.framework/Versions/3.7/lib/python3.7/concurrent/futures/thread.py", line 57, in run
result = self.fn(*self.args, **self.kwargs)
File "/usr/local/lib/python3.7/site-packages/homeassistant/components/media_player/samsungtv.py", line 214, in turn_off
self.get_remote().close()
File "/usr/local/lib/python3.7/site-packages/homeassistant/components/media_player/samsungtv.py", line 138, in get_remote
self._remote = self._remote_class(self._config)
File "/Users/henrik/.homeassistant/deps/lib/python/site-packages/samsungctl/remote.py", line 11, in __init__
self.remote = RemoteWebsocket(config)
File "/Users/henrik/.homeassistant/deps/lib/python/site-packages/samsungctl/remote_websocket.py", line 30, in __init__
self._read_response()
File "/Users/he
Same problem on UE50MU6100. Running HA on HASSIO. He find the name of the device but can’t control the tv.
Failed to call service media_player/turn_off. {'event': 'ms.channel.unauthorized'}
I got this as well when pressing the on/off.
Samsung Tv Nu8000 (2018)
media_player:
- platform: samsungtv
host: xxx.xxx.xxx.xxx
port: 8001
name: Samsung TV
timeout: 30
mac: 64:1c:ae:11:14:d5
After Update to 0.91.0 changing the Line 11 to
import homeassistant.components.samsungtv.media_player as stv
does the trick and the component is working again
greetings
where is the file where you changed?
In my setup this is the media_player.py file which is located in the custom_components/samsungtv_custom directory.
Hi,
I wonder what to do about the warnings I am getting that for all custom components all dependencies need to be included in the custom component. Which files should we move to the samsungtv_custom directory? How should the includes change in the media_player.py file which contains the samsungtv_custom code?
I tried this but not much luck. I do see the TV comes, but it takes like 3-5 minutes before that happens and when turning my tv off manually, HA doesn’t reflect that. I do also get errors when trying to set the Voume:
Traceback (most recent call last):
File “/usr/local/lib/python3.7/site-packages/homeassistant/components/websocket_api/commands.py”, line 122, in handle_call_service
connection.context(msg))
File “/usr/local/lib/python3.7/site-packages/homeassistant/core.py”, line 1138, in async_call
self._execute_service(handler, service_call))
File “/usr/local/lib/python3.7/site-packages/homeassistant/core.py”, line 1160, in _execute_service
await handler.func(service_call)
File “/usr/local/lib/python3.7/site-packages/homeassistant/helpers/entity_component.py”, line 188, in handle_service
self._platforms.values(), func, call, service_name
File “/usr/local/lib/python3.7/site-packages/homeassistant/helpers/service.py”, line 314, in entity_service_call
future.result() # pop exception if have
File “/usr/local/lib/python3.7/site-packages/homeassistant/helpers/service.py”, line 330, in _handle_service_platform_call
await func(entity, data)
File “/usr/local/lib/python3.7/concurrent/futures/thread.py”, line 57, in run
result = self.fn(*self.args, **self.kwargs)
File “/usr/local/lib/python3.7/site-packages/homeassistant/components/media_player/init.py”, line 504, in set_volume_level
raise NotImplementedError()
NotImplementedErrorTraceback (most recent call last):
File “/usr/local/lib/python3.7/site-packages/homeassistant/components/websocket_api/commands.py”, line 122, in handle_call_service
connection.context(msg))
File “/usr/local/lib/python3.7/site-packages/homeassistant/core.py”, line 1138, in async_call
self._execute_service(handler, service_call))
File “/usr/local/lib/python3.7/site-packages/homeassistant/core.py”, line 1160, in _execute_service
await handler.func(service_call)
File “/usr/local/lib/python3.7/site-packages/homeassistant/helpers/entity_component.py”, line 188, in handle_service
self._platforms.values(), func, call, service_name
File “/usr/local/lib/python3.7/site-packages/homeassistant/helpers/service.py”, line 314, in entity_service_call
future.result() # pop exception if have
File “/usr/local/lib/python3.7/site-packages/homeassistant/helpers/service.py”, line 330, in _handle_service_platform_call
await func(entity, data)
File “/usr/local/lib/python3.7/concurrent/futures/thread.py”, line 57, in run
result = self.fn(*self.args, **self.kwargs)
File “/usr/local/lib/python3.7/site-packages/homeassistant/components/media_player/init.py”, line 504, in set_volume_level
raise NotImplementedError()
NotImplementedError
How does your samsungtv.py fole look like?
I changed the directory according to the changes in the update description to:
/custom_component/samsungtv_custom/media_player.py
. (simply renamed the old samsungtv_custom.py
to media_player.py
)
Changed is only Line 11 → here block 9 - 16
import voluptuous as vol
import homeassistant.components.samsungtv.media_player as stv
from homeassistant.components.media_player import (DOMAIN)
from homeassistant.const import (ATTR_ENTITY_ID)
import homeassistant.helpers.config_validation as cv_LOGGER = logging.getLogger(name)
Did the folder change as well, by py file looks like this (line 7-20):
import logging
import socket
from bs4 import BeautifulSoup
import homeassistant.components.samsungtv.media_player as stv
#import voluptuous as vol
from homeassistant.components.media_player import (
SUPPORT_SELECT_SOURCE, SUPPORT_TURN_OFF, SUPPORT_VOLUME_MUTE, SUPPORT_VOLUME_SET,
SUPPORT_VOLUME_STEP, MediaPlayerDevice, PLATFORM_SCHEMA, SUPPORT_TURN_ON)
from homeassistant.const import (
CONF_HOST, CONF_NAME, STATE_OFF, STATE_ON, STATE_UNKNOWN, CONF_PORT,
CONF_MAC)
import homeassistant.helpers.config_validation as cv
Can you link / post the entire file?
as i mentioned the folder structure changed, so you have to rename both the folder where the file is in to samsungtv_custom
and the file itself to media_player.py
.
my media_player.py in /custom_components/samsungtv_custom/
looks like the original only line changed is 11:
""" Custom component to allow overriding or adding features to the samsungtv media_player component. For more details about this platform, please refer to the documentation at https://home-assistant.io/components/media_player.samsungtv/ """ import logging import voluptuous as vol import homeassistant.components.samsungtv.media_player as stv from homeassistant.components.media_player import (DOMAIN) from homeassistant.const import (ATTR_ENTITY_ID) import homeassistant.helpers.config_validation as cv _LOGGER = logging.getLogger(__name__) SAMSUNG_TV_CUSTOM_DATA = 'samsungtv_custom' SERVICE_KEY = 'send_key' # Service call validation schemas ATTR_KEY = 'key_code' SAMSUNG_TV_CUSTOM_KEY_SCHEMA = vol.Schema({ vol.Required(ATTR_ENTITY_ID): cv.entity_ids, vol.Required(ATTR_KEY): cv.string, }) def setup_platform(hass, config, add_devices, discovery_info=None): if SAMSUNG_TV_CUSTOM_DATA not in hass.data: hass.data[SAMSUNG_TV_CUSTOM_DATA] = [] # Use this to get my hands on the SamsungTVDevices that get added def add_devices_custom(devices): add_devices(devices) for device in devices: hass.data[SAMSUNG_TV_CUSTOM_DATA].append(device) # pass in my add_devices_custom function stv.setup_platform(hass, config, add_devices_custom, discovery_info) _LOGGER.debug("hass.data[SAMSUNG_TV_CUSTOM_DATA] = %s.", hass.data[SAMSUNG_TV_CUSTOM_DATA]) def service_handle(service): _LOGGER.debug("service_handle called for %s with %s", service.service, service.data) entity_ids = service.data.get('entity_id') devices = hass.data[SAMSUNG_TV_CUSTOM_DATA] for device in devices: if device.entity_id in entity_ids: if service.service == SERVICE_KEY: device.send_key(service.data.get(ATTR_KEY)) device.schedule_update_ha_state(True) hass.services.register( DOMAIN, SERVICE_KEY, service_handle, schema=SAMSUNG_TV_CUSTOM_KEY_SCHEMA)
I already did that, so I hope I’m on the way.
Hmm your file doesn’t seem to be that long. I just checked the original file and that is also way longer:
Here is mine:
"""
Support for interface with an Samsung TV.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/media_player.samsungtv/
"""
import logging
import socket
from bs4 import BeautifulSoup
import homeassistant.components.samsungtv.media_player as stv
#import voluptuous as vol
from homeassistant.components.media_player import (
SUPPORT_SELECT_SOURCE, SUPPORT_TURN_OFF, SUPPORT_VOLUME_MUTE, SUPPORT_VOLUME_SET,
SUPPORT_VOLUME_STEP, MediaPlayerDevice, PLATFORM_SCHEMA, SUPPORT_TURN_ON)
from homeassistant.const import (
CONF_HOST, CONF_NAME, STATE_OFF, STATE_ON, STATE_UNKNOWN, CONF_PORT,
CONF_MAC)
import homeassistant.helpers.config_validation as cv
REQUIREMENTS = ['wakeonlan==0.2.2', 'beautifulsoup4==4.6.0']
_LOGGER = logging.getLogger(__name__)
CONF_TIMEOUT = 'timeout'
DEFAULT_NAME = 'Samsung TV Remote'
DEFAULT_PORT = 55000
DEFAULT_TIMEOUT = 0
KNOWN_DEVICES_KEY = 'samsungtv_known_devices'
SUPPORT_SAMSUNGTV = SUPPORT_SELECT_SOURCE | SUPPORT_VOLUME_SET | \
SUPPORT_VOLUME_STEP | SUPPORT_VOLUME_MUTE | SUPPORT_TURN_OFF
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Required(CONF_HOST): cv.string,
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
vol.Optional(CONF_PORT, default=DEFAULT_PORT): cv.port,
vol.Optional(CONF_TIMEOUT, default=DEFAULT_TIMEOUT): cv.positive_int,
})
# pylint: disable=unused-argument
def setup_platform(hass, config, add_devices, discovery_info=None):
"""Set up the Samsung TV platform."""
known_devices = hass.data.get(KNOWN_DEVICES_KEY)
if known_devices is None:
known_devices = set()
hass.data[KNOWN_DEVICES_KEY] = known_devices
# Is this a manual configuration?
if config.get(CONF_HOST) is not None:
host = config.get(CONF_HOST)
port = config.get(CONF_PORT)
name = config.get(CONF_NAME)
mac = config.get(CONF_MAC)
timeout = config.get(CONF_TIMEOUT)
elif discovery_info is not None:
tv_name = discovery_info.get('name')
model = discovery_info.get('model_name')
host = discovery_info.get('host')
name = "{} ({})".format(tv_name, model)
port = DEFAULT_PORT
timeout = DEFAULT_TIMEOUT
mac = None
else:
_LOGGER.warning("Cannot determine device")
return
# Only add a device once, so discovered devices do not override manual
# config.
ip_addr = socket.gethostbyname(host)
if ip_addr not in known_devices:
known_devices.add(ip_addr)
add_devices([SamsungTVDevice(host, port, name, timeout, mac)])
_LOGGER.info("Samsung TV %s:%d added as '%s'", host, port, name)
else:
_LOGGER.info("Ignoring duplicate Samsung TV %s:%d", host, port)
class SamsungTVDevice(MediaPlayerDevice):
"""Representation of a Samsung TV."""
def __init__(self, host, port, name, timeout, mac):
"""Initialize the Samsung device."""
from wakeonlan import wol
# Save a reference to the imported classes
self._name = name
self._mac = mac
self._wol = wol
# Assume that the TV is not muted
self._muted = False
self._volume = 0
self._state = STATE_OFF
# Generate a configuration for the Samsung library
self._config = {
'name': 'HomeAssistant',
'description': name,
'id': 'ha.component.samsung',
'port': 7676,
'host': host,
'timeout': timeout,
}
self._selected_source = ''
self._source_names = self.SendSOAP('smp_4_', 'urn:samsung.com:service:MainTVAgent2:1', 'GetSourceList', '', 'sourcetype')
if self._source_names:
del self._source_names[0]
self._source_ids = self.SendSOAP('smp_4_', 'urn:samsung.com:service:MainTVAgent2:1', 'GetSourceList', '', 'id')
self._sources = dict(zip(self._source_names, self._source_ids))
else:
self._source_names = {}
self._source_ids = {}
self._sources = {}
def update(self):
"""Retrieve the latest data."""
currentvolume = self.SendSOAP('smp_17_', 'urn:schemas-upnp-org:service:RenderingControl:1', 'GetVolume', '<InstanceID>0</InstanceID><Channel>Master</Channel>','currentvolume')
if currentvolume:
self._volume = int(currentvolume) / 100
currentmute = self.SendSOAP('smp_17_', 'urn:schemas-upnp-org:service:RenderingControl:1', 'GetMute', '<InstanceID>0</InstanceID><Channel>Master</Channel>','currentmute')
if currentmute == '1':
self._muted = True
else:
self._muted = False
source = self.SendSOAP('smp_4_', 'urn:samsung.com:service:MainTVAgent2:1', 'GetCurrentExternalSource', '','currentexternalsource')
self._selected_source = source
self._state = STATE_ON
return True
else:
self._state = STATE_OFF
return False
def SendSOAP(self,path,urn,service,body,XMLTag):
CRLF = "\r\n"
xmlBody = "";
xmlBody += '<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">'
xmlBody += '<s:Body>'
xmlBody += '<u:{service} xmlns:u="{urn}">{body}</u:{service}>'
xmlBody += '</s:Body>'
xmlBody += '</s:Envelope>'
xmlBody = xmlBody.format(urn = urn, service = service, body = body)
soapRequest = "POST /{path} HTTP/1.0%s" % (CRLF)
soapRequest += "HOST: {host}:{port}%s" % (CRLF)
soapRequest += "CONTENT-TYPE: text/xml;charset=\"utf-8\"%s" % (CRLF)
soapRequest += "SOAPACTION: \"{urn}#{service}\"%s" % (CRLF)
soapRequest += "%s" % (CRLF)
soapRequest += "{xml}%s" % (CRLF)
soapRequest = soapRequest.format(host = self._config['host'], port = self._config['port'], xml = xmlBody, path = path, urn = urn, service = service)
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.settimeout(0.5)
client.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
dataBuffer = ''
response_xml = ''
_LOGGER.info("Samsung TV sending: %s", soapRequest)
try:
client.connect( (self._config['host'], self._config['port']) )
client.send(bytes(soapRequest, 'utf-8'))
while True:
dataBuffer = client.recv(4096)
if not dataBuffer: break
response_xml += str(dataBuffer)
except socket.error as e:
return
response_xml = bytes(response_xml, 'utf-8')
response_xml = response_xml.decode(encoding="utf-8")
response_xml = response_xml.replace("<","<")
response_xml = response_xml.replace(">",">")
response_xml = response_xml.replace(""","\"")
_LOGGER.info("Samsung TV received: %s", response_xml)
if XMLTag:
soup = BeautifulSoup(str(response_xml), 'html.parser')
xmlValues = soup.find_all(XMLTag)
xmlValues_names = [xmlValue.string for xmlValue in xmlValues]
if len(xmlValues_names)== 1:
return xmlValues_names[0]
else:
return xmlValues_names
else:
return response_xml[response_xml.find('<s:Envelope'):]
@property
def name(self):
"""Return the name of the device."""
return self._name
@property
def state(self):
"""Return the state of the device."""
return self._state
@property
def volume_level(self):
"""Volume level of the media player (0..1)."""
return self._volume
@property
def is_volume_muted(self):
"""Boolean if volume is currently muted."""
return self._muted
@property
def source(self):
"""Return the current input source."""
return self._selected_source
@property
def source_list(self):
"""List of available input sources."""
return self._source_names
@property
def media_title(self):
"""Title of current playing media."""
return self._selected_source
@property
def supported_features(self):
"""Flag media player features that are supported."""
if self._mac:
return SUPPORT_SAMSUNGTV | SUPPORT_TURN_ON
return SUPPORT_SAMSUNGTV
def select_source(self, source):
"""Select input source."""
self.SendSOAP('smp_4_', 'urn:samsung.com:service:MainTVAgent2:1', 'SetMainTVSource', '<Source>'+source+'</Source><ID>' + self._sources[source] + '</ID><UiID>0</UiID>','')
def turn_off(self):
"""Turn off media player."""
def set_volume_level(self, volume):
"""Volume up the media player."""
volset = str(round(volume * 100))
self.SendSOAP('smp_17_', 'urn:schemas-upnp-org:service:RenderingControl:1', 'SetVolume', '<InstanceID>0</InstanceID><DesiredVolume>' + volset + '</DesiredVolume><Channel>Master</Channel>','')
def volume_up(self):
"""Volume up the media player."""
volume = self._volume + 0.01
self.set_volume_level(volume)
def volume_down(self):
"""Volume down media player."""
volume = self._volume - 0.01
self.set_volume_level(volume)
def mute_volume(self, mute):
"""Send mute command."""
if self._muted == True:
doMute = '0'
else:
doMute = '1'
self.SendSOAP('smp_17_', 'urn:schemas-upnp-org:service:RenderingControl:1', 'SetMute', '<InstanceID>0</InstanceID><DesiredMute>' + doMute + '</DesiredMute><Channel>Master</Channel>','')
def turn_on(self):
"""Turn the media player on."""
if self._mac:
self._wol.send_magic_packet(self._mac)
Sorry I just can’t see it.
dunni, can post it again, but its a 58 Rows long py file. perhaps im not using the newest version, got mine out of this forum
You can try pm it to me. Yours is working, so that’s all I need as well
EDIT: I tried yours with thr 58 lines of code. Kinda works - I can see when my Samsung is On and Off, but I can’t control anything at all