core: Samsung TV's not working [Testing fix]
*****UPDATED***** PLEASE READ ALL THE INFORMATION BELOW THERE ARE PARTS THAT HAVE CHANGED
I am moving the conversation that is taking place in #17802 as the current conversation really has nothing to do with the issue that was reported.
If this is not OK then delete this issue. I am the person that is currently updating the code to samsungctl. It has undergone a lot of additions which I do believe the users of Home Assistant will enjoy being able to use.
thee library also now supports ALL Samsung TV’s that have the capability of being controlled over a network or WiFi Connection from 2008 to present. This includes the encrypted websocket connections (H (2014) and J (2015) TV’s) as well as the SSL websocket connection (latest firmware release).
I have simplified the connection process so that the only things that are needed in thee Home Assistant config file is the host (ip) of the TV. nothing else is needed. the samsungctl library now handles hammering all of the connection specific details. I also added to it a a class that handles loading and saving of config data. I did this to handle the dynamically changing tokens that are used with the encrypted websockets and SSL websockets. the library now also does not stop running if the connection get severed… (TV gets powered off). I also changed the handling of the power keys to make them function like they should. KEY_POWER = power toggle, KEY_POWERON = power on and KEY_POWEROFF = power off.
I am currently testing the replacement for /homeassistant/components/media_player/samsungtv.py, because I am not familiar with Home Assistant it is better to hammer these problems out in an issue where they can be tested then to open a PR for non functioning code and end up with a very messy commit history.
PLEASE READ
This is a replacement for the /homeassistant/components/media_player/samsungtv.py file please do not edit the code and then report an issue. only report problems relating to this code. also do not provide vague errors. like it says config error… I am willing to bet the error stats more then “config error”. I need a copy of the error message in it’s entirety. not little bits and pieces. because of the nature of Home Assistant you may need to scroll back in the logs and read for a bit to make sure that you have grabbed all of the relevant log messages.
If you state anything about “custom_components” or if i see that in any of the errors I am not going to answer you. this is because you have modified the code. and it is a pretty good chance that your modification is what is causing the problem.
If you do not do the above then I have no way of helping to solve any issues.
config files for the TV are going to be saved in a directory called samsung_tv that is located in the Home Assistant config folder. the config files for the TVs are going to be named using the IP address you supply in the Home Assistant config yaml file.
HOME ASSISTANT CONFIG FILE This is the only thing that needs to be added to your hass configuration.yaml file. you will not need to specify any kind of a host. or mac or name. nothing. The whole system will dynamically add TV’s as it finds them (of coarse with your permission). if a TV is found you will get a notification in the hass UI. when you open this notification you will be prompted to change the display name, the mac address and the description. if you do not wish to change them simply click on the accept button. You may need to refresh the page once the device is added for it to show up. If you have more then a single TV you DO NOT need to add multiple entries into the hass config file. You only need to add the below code a single time.
If you do not want to add a TV to hass (not sure why you wouldn’t) simply ignore the notification. it will disappear after 60 seconds. if you change your mind afterwards or you simply miss the timeout you will need to go into thee samsung_tv config directory and delete the file that has an extension of .noinclude
.
media_player:
- platform: samsungtv
the config file will only get saved once there is a successful connection to the TV made. I have changed about the detection mechanism for the 4 different types of connections. I am hoping this is going to be more of a dock solid mechanism of detecting the connection type. IF you have an issue detecting your TV let me know. There are some tasks I will have you do in order to get it to detect the TV properly. I do not own every Samsung TV made so there is no way to test it on my end. so it is up to you guys to follow the bug reporting directions as outline above.
Here is the updated code.
I WILL NOT MAKE CHANGES AND MAKE ANOTHER POST FOR IT. I WILL UPDATE THE CODE BELOW WITH ANY NEW CHANGES AND INFORM YOU THAT THE CODE HAS CHANGED
click to expand
"""
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 asyncio
from datetime import timedelta
import logging
import threading
import os
import uuid
import voluptuous as vol
from homeassistant.components.media_player import (
MEDIA_TYPE_CHANNEL, PLATFORM_SCHEMA, SUPPORT_NEXT_TRACK, SUPPORT_PAUSE,
SUPPORT_PLAY, SUPPORT_PLAY_MEDIA, SUPPORT_PREVIOUS_TRACK, SUPPORT_TURN_OFF,
SUPPORT_TURN_ON, SUPPORT_VOLUME_MUTE, SUPPORT_VOLUME_STEP,
SUPPORT_VOLUME_SET, SUPPORT_SELECT_SOURCE, MediaPlayerDevice)
from homeassistant.const import (
CONF_NAME,
STATE_OFF,
STATE_ON
)
import homeassistant.helpers.config_validation as cv
from homeassistant.util import dt as dt_util
REQUIREMENTS = [
'https://github.com/kdschlosser/'
'samsungctl/archive/develop.zip#samsungctl==0.8.64b'
]
SAMSUNG_CONFIG_PATH = 'samsung_tv'
ICON_TV = 'mdi:television'
ICON_TV_OFF = 'mdi:television-off'
ICON_COMPONENT = 'mdi:video-input-component'
ICON_HDMI = 'mdi:video-input-hdmi'
ICON_SVIDEO = 'mdi:video-input-svideo'
ICON_USB = 'mdi:usb'
ICON_PC = 'mdi:console'
ICON_DLNA = 'mdi:dlna'
ICON_AV = 'mdi:audio-video'
ICON_YOUTUBE = 'mdi:youtube'
ICON_HULU = 'mdi:hulu'
ICON_NETFLIX = 'mdi:netflix'
ICON_PLEX = 'mdi:plex'
ICON_SPOTIFY = 'mdi:spotify'
ICON_AMAZON = 'mdi:amazon'
ICON_PLAYSTATION = 'mdi:playstation'
ICON_UNKNOWN = 'mdi:help'
_LOGGER = logging.getLogger(__name__)
CONF_DESCRIPTION = 'description'
CONF_ADD = 'add_tv'
KEY_PRESS_TIMEOUT = 1.2
KNOWN_DEVICES_KEY = 'samsungtv_known_devices'
SUPPORT_SAMSUNGTV = (
SUPPORT_PAUSE |
SUPPORT_VOLUME_STEP |
SUPPORT_VOLUME_MUTE |
SUPPORT_PREVIOUS_TRACK |
SUPPORT_NEXT_TRACK |
SUPPORT_TURN_OFF |
SUPPORT_PLAY |
SUPPORT_PLAY_MEDIA |
SUPPORT_VOLUME_SET |
SUPPORT_SELECT_SOURCE
)
SAMSUNG_TV_SCHEMA = vol.Schema({
vol.Optional(CONF_NAME): cv.string,
vol.Optional(CONF_DESCRIPTION): cv.string,
vol.Optional(CONF_ADD): cv.boolean,
})
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({})
_CONFIGURING = {}
def setup_platform(hass, config, add_entities, _=None):
"""Set up the Samsung TV platform."""
config_path = hass.config.path(SAMSUNG_CONFIG_PATH)
if not os.path.exists(config_path):
os.mkdir(config_path)
known_devices = hass.data.get(KNOWN_DEVICES_KEY, set())
hass.data[KNOWN_DEVICES_KEY] = known_devices
import samsungctl
from samsungctl.upnp.discover import auto_discover
config_files = list(
os.path.join(config_path, file) for file in os.listdir(config_path)
if file.endswith('config')
)
def callback(found_config):
if found_config.uuid in known_devices:
return
_LOGGER.debug(str(found_config))
known_devices.add(found_config.uuid)
no_include = os.path.join(
config_path,
found_config.uuid + '.noinclude'
)
if os.path.exists(no_include):
return
if found_config.uuid not in _CONFIGURING:
add_device(found_config, hass, config_path, add_entities)
auto_discover.register_callback(callback)
entities = []
configs = []
for config_file in config_files:
_LOGGER.debug(config_file)
samsung_config = samsungctl.Config.load(config_file)
known_devices.add(samsung_config.uuid)
configs += [samsung_config]
auto_discover.start()
for samsung_config in configs:
entities += [SamsungTVDevice(samsung_config)]
add_entities(entities)
def add_device(samsung_config, hass, config_path, add_entities):
model = samsung_config.model
uuid = samsung_config.uuid
event = threading.Event()
def samsung_configuration_callback(data):
"""Handle the entry of user PIN."""
display_name = data.get('display_name')
description = data.get('description')
mac = data.get('mac')
if display_name is None:
display_name = samsung_config.display_name
if description is None:
description = samsung_config.description
if mac is None:
mac = samsung_config.mac
samsung_config.display_name = display_name
samsung_config.description = description
samsung_config.mac = mac
samsung_config.path = os.path.join(
config_path,
samsung_config.uuid + '.config'
)
hass.components.configurator.request_done(_CONFIGURING.pop(uuid))
if samsung_config.method == 'encrypted':
request_configuration(samsung_config, hass, add_entities)
else:
add_entities([SamsungTVDevice(samsung_config)])
event.set()
def do():
event.wait(600.0)
if not event.isSet():
path = os.path.join(
config_path,
samsung_config.uuid + '.noinclude'
)
with open(path, 'w') as f:
f.write('')
hass.components.configurator.request_done(_CONFIGURING.pop(uuid))
t = threading.Thread(target=do)
t.daemon = True
t.start()
_CONFIGURING[uuid] = hass.components.configurator.request_config(
model,
samsung_configuration_callback,
description='New TV discovered, would you like to add the TV?',
description_image="/static/images/smart-tv.png",
submit_caption="Accept",
fields=[
dict(
id='display_name',
name='Name: ' + samsung_config.display_name,
type=''
),
dict(
id='description',
name='Description: ' + samsung_config.description,
type=''
),
dict(
id='mac',
name='MAC Address : ' + str(samsung_config.mac),
type=''
)
]
)
def request_configuration(samsung_config, hass, add_entities):
"""Request configuration steps from the user."""
configurator = hass.components.configurator
import samsungctl
pin = []
count = 0
event = threading.Event()
def samsung_configuration_callback(data):
"""Handle the entry of user PIN."""
pin.append(data.get('pin'))
event.set()
def get_pin():
global count
if samsung_config.uuid in _CONFIGURING:
count += 1
event.clear()
del pin[:]
configurator.notify_errors(
_CONFIGURING[samsung_config.uuid],
"Failed to register, please try again."
)
else:
_CONFIGURING[samsung_config.uuid] = configurator.request_config(
samsung_config.display_name,
samsung_configuration_callback,
description='Enter the Pin shown on your Samsung TV.',
description_image="/static/images/smart-tv.png",
submit_caption="Confirm",
fields=[{'id': 'pin', 'name': 'Enter the pin', 'type': ''}]
)
event.wait(60.0)
if count == 3:
_LOGGER.error(
samsung_config.display_name + " TV: Pin entry failed"
)
return False
elif not event.isSet():
return None
return pin[0]
samsung_config.get_pin = get_pin
def do():
global count
try:
_ = samsungctl.Remote(samsung_config)
add_entities([SamsungTVDevice(samsung_config)])
except:
pass
hass.components.configurator.request_done(_CONFIGURING.pop(uuid))
t = threading.Thread(target=do)
t.daemon = True
t.start()
class SamsungTVDevice(MediaPlayerDevice):
"""Representation of a Samsung TV."""
def __init__(self, config):
"""Initialize the Samsung device."""
from samsungctl import exceptions
from samsungctl import Remote
# Save a reference to the imported classes
self._exceptions_class = exceptions
self._remote_class = Remote
self._config = config
self._mac = self._config.mac
self._uuid = self._config.uuid
self._playing = True
self._state = None
self._remote = None
self._key_source = False
self._mute = False
self._sources = []
self._source = ''
self._volume = 0.0
self._entity_image = None
self._tv_image = None
if self._config.method == 'websocket':
self._has_apps = True
else:
self._has_apps = False
self._icon = ICON_TV_OFF
self._supported_features = SUPPORT_SAMSUNGTV
if self._config.method != 'legacy':
self._supported_features |= SUPPORT_TURN_ON
# Mark the end of a shutdown command (need to wait 15 seconds before
# sending the next command to avoid turning the TV back ON).
self._end_of_power_off = None
# Mark the end of the TV powering on.need to wait 20 seconds before
# sending any commands.
self._end_of_power_on = None
# Generate a configuration for the Samsung library
self._remote = self._remote_class(self._config)
def update(self):
"""Update state of device."""
if self._power_off_in_progress():
_LOGGER.debug(
self._config.display_name + ' TV: Powering Off'
)
self._state = STATE_OFF
self._icon = ICON_TV_OFF
# self._entity_image = self._tv_image
elif self._power_on_in_progress():
_LOGGER.debug(
self._config.display_name + ' TV: Powering On'
)
self._state = STATE_OFF
self._icon = ICON_TV_OFF
# self._entity_image = self._tv_image
else:
power = self._remote.power
if power is True and self._remote.is_connected:
self._config.save()
if self._tv_image is None:
tv_image = self._remote.icon
if tv_image is not None:
self._tv_image = tv_image.data
sources = self._remote.sources
entity_image = self._tv_image
source = 'Unknown'
if sources is None:
if self._has_apps:
sources = [
'TV',
'HDMI'
]
for app in self._remote.applications:
if app.is_running and app.is_visible:
source = 'APP: ' +app.name
entity_image = app.icon
sources += ['APP: ' + app.name]
self._sources = sources
self._source = source
self._entity_image = entity_image
else:
self._sources = [
'Source',
'Component 1',
'Component 2',
'AV 1',
'AV 2',
'AV 3',
'S Video 1',
'S Video 2',
'S Video 3',
'HDMI',
'HDMI 1',
'HDMI 2',
'HDMI 3',
'HDMI 4',
'FM-Radio',
'DVI',
'DVR',
'TV',
'Analog TV',
'Digital TV'
]
self._key_source = True
else:
new_sources = []
for src in sources:
if src.is_active:
if src.label != src.name:
source = src.label + ':' + src.name
else:
source = src.name
if src.name != src.label:
new_sources += [src.label + ':' + src.name]
else:
new_sources += [src.name]
self._key_source = False
self._sources = new_sources[:]
self._source = source
# self._entity_image = entity_image
if self._source.upper().endswith('TV'):
self._icon = ICON_TV
elif self._source.upper().endswith('USB'):
self._icon = ICON_USB
elif self._source.upper().endswith('PC'):
self._icon = ICON_PC
elif self._source.upper().endswith('DLNA'):
self._icon = ICON_DLNA
elif 'S VIDEO' in self._source.upper():
self._icon = ICON_SVIDEO
elif 'COMPONENT' in self._source.upper():
self._icon = ICON_COMPONENT
elif 'AV' in self._source.upper():
self._icon = ICON_AV
elif 'HDMI' in self._source.upper():
self._icon = ICON_HDMI
elif 'YOUTUBE' in self._source.upper():
self._icon = ICON_YOUTUBE
elif 'HULU' in self._source.upper():
self._icon = ICON_HULU
elif 'NETFLIX' in self._source.upper():
self._icon = ICON_NETFLIX
elif 'PLEX' in self._source.upper():
self._icon = ICON_PLEX
elif 'SPOTIFY' in self._source.upper():
self._icon = ICON_SPOTIFY
elif 'AMAZON' in self._source.upper():
self._icon = ICON_AMAZON
elif 'PLAYSTATION' in self._source.upper():
self._icon = ICON_PLAYSTATION
else:
self._icon = ICON_UNKNOWN
volume = self._remote.volume
_LOGGER.debug(
self._config.display_name + ' TV: Volume = ' + str(volume)
)
if volume is not None:
self._volume = volume / 100.0
mute = self._remote.mute
_LOGGER.debug(
self._config.display_name + ' TV: Mute = ' + str(mute)
)
if mute is None:
self._mute = False
else:
self._mute = mute
_LOGGER.debug(
self._config.display_name + ' TV: Power is On'
)
self._state = STATE_ON
else:
_LOGGER.debug(
self._config.display_name + ' TV: Power is Off'
)
# self._entity_image = self._tv_image
self._icon = ICON_TV_OFF
self._state = STATE_OFF
def send_key(self, key):
"""Send a key to the tv and handles exceptions."""
if self._power_off_in_progress():
_LOGGER.info(
self._config.display_name +
" TV: powering off, not sending command: %s",
key
)
return
elif self._power_on_in_progress():
_LOGGER.info(
self._config.display_name +
" TV: powering on, not sending command: %s",
key
)
return
if self._state == STATE_OFF:
_LOGGER.info(
self._config.display_name +
" TV: powered off, not sending command: %s",
key
)
return
self._remote.control(key)
@property
def icon(self):
"""Return the icon to use in the frontend, if any."""
return self._icon
@property
def entity_picture(self):
"""Return the entity picture to use in the frontend, if any."""
return self._entity_image
@property
def unique_id(self) -> str:
"""Return the unique ID of the device."""
return '{' + self._config.uuid + '}'
@property
def name(self):
"""Return the name of the device."""
return self._config.display_name
@property
def state(self):
"""Return the state of the device."""
return self._state
@property
def supported_features(self):
"""Flag media player features that are supported."""
return self._supported_features
def select_source(self, source):
"""Select input source."""
if self._key_source:
if source == 'Analog TV':
source = 'ANTENA'
elif source == 'Digital TV':
source = 'DTV'
source = source.upper().replace('-', '_').replace(' ', '')
source = 'KEY_' + source
_LOGGER.debug(
self._config.display_name + ' TV: changing source to ' + source
)
self.send_key(source)
else:
if 'APP' in source:
app_name = source.rsplit(':', 1)[-1]
app = self._remote.get_application(app_name)
if app is not None:
app.run()
if ':' in source:
source = source.rsplit(':', 1)[-1]
_LOGGER.debug(
self._config.display_name + ' TV: changing source to ' + source
)
self._remote.source = source
@property
def source(self):
"""Name of the current input source."""
return self._source
@property
def source_list(self):
"""List of available input sources."""
return self._sources
def volume_up(self):
"""Volume up the media player."""
self.send_key('KEY_VOLUP')
def volume_down(self):
"""Volume down media player."""
self.send_key('KEY_VOLDOWN')
@property
def volume_level(self):
"""Volume level of the media player scalar volume. 0.0-1.0."""
return self._volume
def set_volume_level(self, volume):
"""Set volume level, convert scalar volume. 0.0-1.0 to percent 0-100"""
self._remote.volume = int(volume * 100)
def mute_volume(self, mute):
"""Send mute command."""
self._remote.mute = mute
@property
def is_volume_muted(self):
"""Boolean if volume is currently muted."""
return self._mute
def media_play_pause(self):
"""Simulate play pause media player."""
if self._playing:
self.media_pause()
else:
self.media_play()
def media_play(self):
"""Send play command."""
self._playing = True
self.send_key('KEY_PLAY')
def media_pause(self):
"""Send media pause command to media player."""
self._playing = False
self.send_key('KEY_PAUSE')
def media_next_track(self):
"""Send next track command."""
self.send_key('KEY_FF')
def media_previous_track(self):
"""Send the previous track command."""
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(
self._config.display_name + ' TV: Unsupported media type'
)
return
# media_id should only be a channel number
try:
cv.positive_int(media_id)
except vol.Invalid:
_LOGGER.error(
self._config.display_name +
' TV: 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)
@property
def app_id(self):
"""ID of the current running app."""
return None
@property
def app_name(self):
"""Name of the current running app."""
return None
def turn_on(self):
"""Turn the media player on."""
if self._power_on_in_progress():
return
if self._config.mac:
self._end_of_power_on = dt_util.utcnow() + timedelta(seconds=20)
if self._power_off_in_progress():
self._end_of_power_on += (
dt_util.utcnow() - self._end_of_power_off
)
def do():
_LOGGER.debug(
self._config.display_name + ' TV: Power on process started'
)
event = threading.Event()
while self._power_off_in_progress():
event.wait(0.5)
self._remote.power = True
t = threading.Thread(target=do)
t.daemon = True
t.start()
elif self._config.method != 'legacy':
_LOGGER.info(
self._config.display_name +
" TV: There was a problem detecting the TV's MAC address, "
"you will have to update the MAC address in the Home "
"Assistant config file manually."
)
else:
_LOGGER.info(
self._config.display_name +
" TV: Legacy TV's (2008 - 2013) do not support "
"being powered on remotely."
)
def _power_on_in_progress(self):
return (
self._end_of_power_on is not None and
self._end_of_power_on > dt_util.utcnow()
)
def turn_off(self):
"""Turn off media player."""
if self._power_off_in_progress():
return
self._end_of_power_off = dt_util.utcnow() + timedelta(seconds=15)
if self._power_on_in_progress():
self._end_of_power_off += (
dt_util.utcnow() - self._end_of_power_on
)
def do():
_LOGGER.debug(
self._config.display_name + ' TV: Power off process started'
)
event = threading.Event()
while self._power_on_in_progress():
event.wait(0.5)
self._remote.power = False
t = threading.Thread(target=do)
t.daemon = True
t.start()
def _power_off_in_progress(self):
return (
self._end_of_power_off is not None and
self._end_of_power_off > dt_util.utcnow()
)
About this issue
- Original URL
- State: closed
- Created 5 years ago
- Reactions: 14
- Comments: 375 (113 by maintainers)
After HA updates, I have decided to create a custom component, it is working on the latest version of HA 0.99.3, I have uploaded the code to:
https://github.com/roberodin/ha-samsungtv-custom
I hope it helps you.
ok I will tell you where I am at with the library. I need someone that uses the tuner on the TV. a TV that is 2015 or older. I am able to provide a channel lineup with channel names i simply need to know the format of the file.
if you go to this URL in your browser on your PC with the TV on and replacing
YOUR_TV_IP
with the IP of your TV.save the file and zip it up and attach it to an issue in the samsungctl repo.
that is the only thing left for the UPNP end of things. The library is 100% working for legacy TV’s I did some pretty serious housekeeping on the code. and I cleaned up a lot of things and improved the overall performance of the library. The TV discovery is 100% working now. The power state is also working I am in the process of getting the encrypted websocket back into running order. I removed a massive amount of code that was not needed. and removed multiple creations of the aes encryption object that gets used when connecting to the TV. I moved all of thee code that is specific to the TV control into the remote classes. you can see the large code update i did here.
https://github.com/kdschlosser/samsungctl/commit/b52b2ae13a3c418d9ed1b4e7d43187781076fa3e
I have not tested the websocket or websocket ssl portion of the library. I have not had someone that has one of these TV’s offer to help in the debugging
I created a script that will test every single component of the library so helping to test only requires you to install python 2.7 and python 3.5+ install a few modules using pip in both python installations. and then run the test program. then send me the data. everything gets writen to a series of files and from those files I am able to fix issues and i can fix them really quickly.
What I had wanted to do was to add all of the available functionality of samsungctl to hass. and not just volume up and down and power. I have asked several times for guidance/help doing that portion of it and have not heard a peep from anyone. because of how hass is coded an IDE is pretty much useless in the help department. and I simply do not have the time to learn by trial and error. I do have things that require my attention other then a PC. Most of the users here are on the opposite side of the planet from me. But it seems as tho I am the one that is staying up all night working on this thing. Frankly I am getting burnt and I am falling behind with other tasks.
The library works for my TV. so anything i do now with the library is not to my benefit. it is for yours. I should not be the only one that is sacrificing in order to provide you with a way to control your TV. any of the people that have run the test program has seen the amount of data that i have to shuffle through in order to get things working. and being tired does not help.
OK I have not updated anything yet. so continuing to mess around with the one that is posted is not going to get you anywhere. It does not work correctly. II know this. I have been working on it. There are still problems with samsungctl. I need to get those all cleaned up and everything running properly before I am going to do anything with getting it to run in hass. I am sorry but I am not going to be able to get the code updated today. Family business took most of my day. so I was not able to get the last couple of things fixed. I only have a 2-3 hour window for testing so I do not get to work on it all that much. The people that do the testing for me are an 8 hour time difference. so it makes it a bit challenging.
I wanted to let everyone know where we are at with this an not leave ya hanging.
OK so here is the skinny. discovery is working like a champ now. I found out where the issue wa and it is now all sorted out. I am still working out some bugs in the power portion of the program. I think I may have found what the cause is just waiting on a test. websocket, SSL websocket and encrypted are working good. i broke the legacy somehow. still looking into what I did there. all the issues with UPNP have been resolved. I only have the channels to deal with and the UPNP i am almost sure can be stamped COMPLETE. the config portion is working good. no problems there. after i fix the few issues and do up the channels and run some more tests across the 5-6 different models that people are running these tests on if everything works smoothly then I know the backend of the library is functioning like it should and I can move back to working on the hass portion. I would really like to expose more of what these TV’s can do to hass. But I need help doing that. the controls that hass gives doesn’t even scratch the surface of the control that is available. and I do not own any of the components in the components portion of the program. if i did I would be able to load the component and see how thee GUI is done for those items. I guess I could “hotwire” the things so they would display. That is quite a bit of work to do. I need a visual comparison to see if i can make something work for the samsung tv’s So again if there is someone out there that is really knowledgeable about hass and the different “flows” and things of that nature. I could really use the help on that end of it.
I will be updating the samsungctl library some time today. I will also update the code in the first post to work with the updated library.
the only thing you need to do is go into components/media_player/samsungtv.py delete all of the code in that file and paste in the code that is attached to the first post. it will update the samsungctl library as needed.
@sermayoral and @kdschlosser do you guys still need testers? I have take a version of @kdschlosser library and have it running via a custom component in my home assistant so may be able to help some if desired.
For Athom Homey, somebody managed to make a working app. Possibly this could give some clues for the Home assistant module.
https://github.com/balmli/com.samsung.smart/tree/cd455cbb5cb27988e7e32e2489cf604e7135843d
@kdschlosser is the samsungctl library developer. He doesn’t know the Home Assistant code. It is very annoying to understand all the code of a system that you have not developed, and he does not have to do it. We must understand that.
He also asked for help from a Home Assistant developer to help him integrate his code, but no one volunteered.
However, he continues to improve the samsungctl library to support ALL TV models, and some of us are helping him. This is the first step. Without the samsungctl library, nothing is possible in HA with Samsung TVs.
If there is a volunteer who wants to help us to debug samsungctl outside the Home Assistant environment, he just needs basic knowledge of Python, and have a TV model that tells us @kdschlosser
The first step is to complete the samsungctl library. Then we will see who can help us integrating it into Home Assistant. Some developer may see the samsungctl commit and decide to merge it in Home Assistant …
But of course, the first thing is to complete samsungctl. Thanks for everything you are doing @kdschlosser 😃
I have H series TV. I tried multiple components and they never work as expected
Line 89, 90.
@Gamelauncher The quick howto is:
@arsaboo If I had made major modifications I would share but as you can see from my steps above I am just using the existing component with no fancy addons. I am excited to attempt to help integrate some of the new features you guys have been adding.
@kdschlosser I will jump over to that issue and see where I can assist.
@sermayoral, yep, my MU6300 uses ssl websocket. The tv was mostly working in HA before the 1250 Samsung firmware update. There was a fix to adapt the ssl websocket, which made it work again (mostly, on, off, mute, volume) but the tv got another firmware update and stopped working again.
I will gladly help if you need info from my tv. I have a PI2 laying around so I could get it running again and test what you need me to!
hass.io users:
go to the location where the configuration.yaml file is located open the custom_components folder open the media_player folder if it exists. if not make it. create a new fil called “samsungtv.py” thne paste the code form the first post into that new file. restart hass.io
for homeassistant users (pip install of homeassistant) open up your python site-packages folder. from there navigate to the folder homeassistant\components\media_player open the samsungtv.py file. select everything in the file and press delete past in the code form the first post. save the file and restart homeassistant.
thee code form the first post contains all of the code needed to download the version of samsungctl from my Github repository that is needed. when I update the code if you already have samsungctl installed into homeassistant it is going to upgrade\downgrade it to the version that is needed.
@maxkde TY for the complete post of the traceback. i do appreciate it.
I think because of the way samsung TV’s reply encoding is different between years/models as well as different based on the function. we are going to need to do some exception catching here.
so starting at line 114 in action.py which reads
we need to change that to
what is causing the issue is this. if the opening tag in the returned xml is this
then the input needs to be a string. and because response.content in python 3 are bytes we need to decode the information before feeding it into lxml
Now when the return data has this as the first tag
the data fed into lxml needs to be bytes.
it’s a crap shoot what TV is going to return what tag as well as the function. some functions may return the encoding some may not.
ya gotta love the dumb ass programmers at Samsung… they have ZERO consistency
ok i finally found where they are hiding that damned configuration dialog. it comes in as a notification instead of either in a device configuration page or as a simple popup
Update to version 3.0.0 and try the new protocols: -ws (fixed from @xchwarze) -ctl_beta -ctl_qled
https://github.com/roberodin/ha-samsungtv-custom
I can also try and help swap out the current implementation once it gets ready for prime time. I’ve at least contributed to the Samsung TV component in the past (tiny contribution of channel changing) but am willing to help out where I can, when I can! @kdschlosser I’ve got a websocket tv if it helps. Let me know what I can do!
@kdschlosser thank you for the hard work you put in attempting to get this working. My last comment was just wondering what the status was.
@kdschlosser thanks for being so responsive on here despite your family business 😃
The code in the first post will download his version. The maintainer of the Ape library has gone awol and his was forked from that (and then new features added) IIRC he is trying to iron out all the bugs then it will be added to pippy and a PR done on the code for HA to replace the current samsungtv with his version.
The phrase “It cannot be done.” does not fit into my vocabulary. because the person saying it is actually saying “I am to lazy to figure it out.”, I will however accept a substitute of “Given our state of technology at the present time we cannot make it happen.” This is a good replacement because it is not saying that it can’t be done. it is saying it can’t be done right now but in the future, yes.
I have been told my bean does a very good job at solving problems or coming up with crafty ways to accomplish a goal.
Now as far as the remote button eventing… I know this in fact does work with Samsung TV’s (It’s a crap shoot as to what brands do and don’t) I have tested it with my Samsung TV. That is not to say that the dingbats over at Samsung didn’t remove this feature in newer models. I do not have that answer.
The other things is how does one go about creating something the automation pieces of hass can use. That I do not know. so if someone is willing to chime in and explain this system to me then we can have a go at it.
I wanted to throw something out there as an idea. Some time ago I wrote an API for liibcec. for those of you that do not know what libcec is, it is a software package for accessing a CEC interface device. Pulse Eight makes one of these devices. and one is built into Raspberry Pi. Seeing as how a lot of you folks are using raspberry pi’s I thought this would be a geat feature to add into samsungctl. for starters this would give you the direct source change that most of you would like to have. We can also capture events for button presses on the remote. the samsungctl volume control would change over to using libcec for the volume control. so if you have a CEC complient AVR the volume would change on that instead of the TV.
what are the thoughts on that??
@LeidenSpain
this is still an alpha test version. it does not function properly yet. as you can see from the posts I am trying to get as many features from these TV’s as possible. I am really thinking to going out and buying one for 2 weeks and then return it.
on my legacy everything works perfect. but it is different mechanics then the websocket TV’s
I have a HU7500 and basic knowledge about Python (but I’m a developer)
@kdschlosser I’ll be glad to help. I’ve got a QE65Q8FAMT
I have a UE55NU8006 and am willing to help with testing. Joined the slack chat already 😃 @kdschlosser I’ve sent you a DM on slack.
I have a UN75NU8000 that I can test with
@sermayoral
i have it outputting the information to the file requested. I sent you an updated version of samsungctl along with the program for running the tests.
to increase the output buffer of a command prompt if you click on the small icon in the caption bar on the top left of the window. you should see preferences in the drop down menu. in the properties dialog you should have a tab for “Layout”. this is where you will be given the controls to adjust the buffer. you can also adjust the number of columns and rows that are displayed as well.
as far as the serializing issue that is easily corrected as well.
line 434 in the code attached to the first post would need to be changed to
OK I updated the code in the first post.
I changed a bunch of things around. IP addresses are no longer needed to define a TV, this means you do not have to set the TV to a static IP address. I am now relying on a UUID that is unique to each TV. With this change It also altered the power detection. I am now using UPNP to detect if the TV is on or not. so the constant trying to open a socket to detect if the TV is on or not is no longer being used. this has reduced the resource use on the device running the code. it would be more noticeable with multiple TV’s. This is a good thing for you folks running on Raspberries. In my setup only running a single TV it has also reduced the memory footprint a few meg.
I also changed the detection mechanism I am now grabbing the year of the TV via UPNP and using the services as a fallback in case the year is not detected properly. This is going to make for a much more solid detection of the connection type.
I did also change up the inputting of the PIN so the notification will be generated after the pin has been displayed on the TV and not before. I think this may have been causing some issues.
the new code is in the first post. everything needed to have it update samsungctl has been set in place.
@cristimi I am not sure as to why but your TV is not responding to the UPNP SSDP broadcast packets.
@cjsmns as a reminder the pin entry dialog should appear as a notification. The notification to enter the PIN should be working. if you are not getting a notification then I am going to need to need to do some more work on the detection. possibly parsing the model number. I think that is what I am going to do.
@phairplay OK so the first piece is tackled. we are now moving onto the power detection once again. I am working on this aspect of it.
I am in the process of changing the library to not be dependant on the IP address of the TV. I am putting more work into the UPNP end of things. this is going to be the way to go about detecting the TV’s state and also locating new TV’s added to your network.
so basically having to set your TV to a static IP will not have to be done anymore. and if you go out and buy a new TV and connect it to your network. hass will almost instantly notify you of the new TV and if you want to add it. no restarts needed!!
those changes will be made in the next 2 days or so. the reasoning for this is instead of trying to constantly open a socket every second or so (resource intensive) i am going to rely on UPNP discovery packets. the UPNP will keep on broadcasting keeping a single socket open and that single socket will handle all of the TV’s on the network. this will by far use less resources it will be a lot more apparent if there are multiple TV’s being handled
@phairplay
I updated the code. and I did add the upnp classes to the discovery correctly for your TV (lucky guess).
You can give the new code in the first post a go. just make sure you delete all of the files in the samsung_tv config path before running hass.
Yep. This is what I have.
I noticed the config issue as well. It is not a big deal because this only gets used for thee actual connection to the TV. thee name that takes presidence and shows in your home assistant GUI is the on that is supplied in the home assistant config file. so it is pretty moot.
That is strange about the power state for the TV. I am going to put the code back to use the socket as the mechanism to determine the state of the TV. I like this mechanism better then making another call to the TV to see if it returns data.
I am guessing you are not able to test anything because the TV s reported as being off.
let me make a quick change and see if it solves your problem
I have most of the things you mentioned repaired. I will be pushing an update soon to samsungctl. We are making progress, albeit slow but at least there is movement in the right direction 😄
as far as the config goes. this is the hard part. because of the 10 second limitations that Home Assistant has in place it is making it difficult to really run a full detection suit. I think I have a way to go about it. that would be really fast and also I would be able to run all 3 detection types at the same time. this would greatly speed up the whole process.
I need the UPNP layout for the 2016+ TV’s. I have for the legacy and for the encrypted once i get the one for the websocket connection II will be able to see which type has what UPNP services. I am willing to bet there is a single unique service to each of the TV types. and if that is the case then I can send out a broadcast for each of the connection types specifically. from there i can determine the connection by seeing who answered what broadcast.
If someone has a newer TV and also have Python installed you can clone this repo
https://github.com/kdschlosser/UPNP_Device/tree/develop
and run
and once it is done installing make sure you have your TV on. and run this command
changing the [IP] to the ip of your TV and changing [DUMP_DIRECTORY] to the directory where you want copied of the UPNP files form the TV dumped into. make sire the directory already exists and it also has to be an absolute path so no $'s or ~'s or %'s
after it finished the directory is going to contain an exact replica of the UPNP paths that the TV has as well as a SSDP.log file. which is a log of the SSDP responses form the TV. I would need the whole directory zipped up exactly how it is.
I am going to do a commit shortly to update the code in the UPNP_Device repo. so you have to give me 15 minutes or so before trying it.
You can also test out setting the TV volume if you wanted. and getting the volume and setting the mute and getting the mute as well.
there may be an additional parameter needed depending on the TV
Mute is pretty much the same deal. just swap out Volume for Mute and you have to specify a 1 or a 0 for the value if setting it.
when you do the dump you will see a whole printout of every upnp function the TV offers. if you want to do that without dumping the data
if you omit thee IP it is going to print out every device on your network.
you can also get help on a specific function. this is going to tell you the arguments that are required and ones that are optional. default values. choices. min and max. crap like that
the --help MUST be after the function
@arsaboo
what do you mean??
@phairplay have a look at this…
I wrote a Sony TV Gen3+ API, I think it is still the most complete API made to date. I could be wrong in that tho. I have a develop branch that has a bunch more added to it. the develop branch is not in a working state and it actually has been a long time since I have put any work into it.
https://github.com/kdschlosser/SonyAPI
@phairplay
also I am starting to think you have a special-ed TV on your hands over there. the thing should be riding the little yellow short bus while wearing a helmet and licking the window. because it’s slowwwww… that is causing the time out problem in the async handler. I am going to move the construction of the remote to the __init__ method and see if that solves the problem . I know there is a 60 second timeout on that.
@phairplay
I am at 8500 feet (2590.8 meters) above sea level. in Colorado (Rocky Mountains) about an hour and a half away from the highest mountain in North America. Put it to ya this way. nearest gas station is a tad over 25 minutes away. (If i drove like the law says I should but since I don’t it takes me about 15). In the last 3 weeks we have gotten 4 feet of snow.
and -20c is nothing. we call that “brisk” here… now when it hits -30c (and it does and stays like that for a month sometimes) that is a might bit chilly. We get this really cool phenomenon that happens. we call it “Thunder Snow”. That is when you have a lightning storm while it is snowing…
from the logs it does appear the TV state is now working correctly. why exactly your TV is not turning on is the question. if the restart does not solve it then I will have to add some code to see what is going on.
@jnimmo No it is sending the command. When Home Assistant checks the source I am returning Unknown
plus I am 45… memory is slipping I do need to go back and see if i have tried something or not… 😉
I am glad to see all of the upnp errors are gone with this version of samsungctl.
I did also want to mention that the power on and power off sequence takes roughly 17 seconds for on and about 12 seconds for off.
do not pay attention to what the TV is doing. just because the screen is on or off is not what dictates when the TV is actually considered on or off. These TV’s are Computers. so when you turn you computer on. just because the screen is on does it mean the computer is booted?? No it does not. so the same thing goes for the TV. it takes a while for the TV to boot up. as well as it takes a while for it to shutdown. so when the websocket service is finally started or stopped (which is one of the last things the TV does) then it is considered on or off.
so be patient when telling it to turn on or off. it may take 20 seconds for the state to change in HomeAssistant. and just like any computer. the newer the TV the faster it will be. and do remember that if you have a lot of applications on it. this can also impact the speed in which the TV boots. Also as a good rule of thumb. the more ding dongs and ho ho’s (features) the TV has the longer it is going to take to boot. so the top of the line samsung TV of this year is probably going to take longer to turn on then say something middle of the road