Testing the timeout fix

Thanks for putting in a fix for the timeout @kdschlosser. I can see you’ve added the LG logging to the file. To test this with my 2017/2018 tv I’m guessing I’ll need to checkout this timeout branch and call the method. What command should I issue? When I tried using this library earlier today diectlty it was giving me errors about bytes so I’m guessing I was missing some parameters.

so yea you will need to checkout this branch git checkout --track origin/timeout_fix
then try to run this python command
import samsungctl

config =  {
        "name": "samsungctl",
        "description": "PC",
        "id": "11",
        "host": "YOUR IP",
        "port": 8002,
        "method": "websocket"
    }

with samsungctl.Remote(config) as remote:
    remote.control("KEY_PLAY")

Thanks. I'm not sure if I'm doing something wrong but I checked out that branch. Then saved the phython above as test.py and then ran it in Thonny. I got the following:
Python 3.5.3 (/usr/bin/python3)
>>> %Run test.py
Traceback (most recent call last):
  File "/home/pi/Documents/Samsungcti-test/test.py", line 12, in <module>
    with samsungctl.Remote(config) as remote:
  File "/home/pi/.local/lib/python3.5/site-packages/samsungctl/remote.py", line 10, in __init__
    self.remote = RemoteWebsocket(config)
  File "/home/pi/.local/lib/python3.5/site-packages/samsungctl/remote_websocket.py", line 22, in __init__
    self._serialize_string(config["name"])), config["timeout"])
KeyError: 'timeout'
>>>

Hmm so I checked my tv is on and on the network and ran a scan to check the ip is correct. Then I ran the script above and get this:
>>> %Run test.py
Traceback (most recent call last):
  File "/home/pi/Documents/Samsungcti-test/test.py", line 13, in <module>
    with samsungctl.Remote(config) as remote:
  File "/home/pi/.local/lib/python3.5/site-packages/samsungctl/remote.py", line 10, in __init__
    self.remote = RemoteWebsocket(config)
  File "/home/pi/.local/lib/python3.5/site-packages/samsungctl/remote_websocket.py", line 22, in __init__
    self._serialize_string(config["name"])), config["timeout"])
  File "/home/pi/.local/lib/python3.5/site-packages/websocket/_core.py", line 487, in create_connection
    websock.connect(url, **options)
  File "/home/pi/.local/lib/python3.5/site-packages/websocket/_core.py", line 214, in connect
    self.handshake_response = handshake(self.sock, *addrs, **options)
  File "/home/pi/.local/lib/python3.5/site-packages/websocket/_handshake.py", line 69, in handshake
    status, resp = _get_resp_headers(sock)
  File "/home/pi/.local/lib/python3.5/site-packages/websocket/_handshake.py", line 127, in _get_resp_headers
    status, resp_headers = read_headers(sock)
  File "/home/pi/.local/lib/python3.5/site-packages/websocket/_http.py", line 226, in read_headers
    line = recv_line(sock)
  File "/home/pi/.local/lib/python3.5/site-packages/websocket/_socket.py", line 101, in recv_line
    c = recv(sock, 1)
  File "/home/pi/.local/lib/python3.5/site-packages/websocket/_socket.py", line 93, in recv
    "Connection is already closed.")
websocket._exceptions.WebSocketConnectionClosedException: Connection is already closed.
>>>

I'm struggling a while with samsungctl. I'm pretty new with python and a programmer for work. But I can read most of the code without problems. I want to help fixing this issue. I own a Samsung TV Q7F 2017 model. I run the 'program' samsungctl on a Raspberry pi. When i run the program i get the following output :
{
"data": {
"id": "5c786543-cfc2-4820-8a4f-d323113c78dc",
"token": "17223081",
"clients": [
{
"attributes": {
"name": "c2Ftc3VuZ2N0bA=="
},
"connectTime":<PHONE_NUMBER>926,
"deviceName": "c2Ftc3VuZ2N0bA==",
"id": "5c786543-cfc2-4820-8a4f-d323113c78dc",
"isHost": false
}
]
},
"event": "ms.channel.connect"
}
Error: Permission denied
Looks like there is something going wrong with the Token but i'm not sure how to solve it. What am i doing wrong or could i test some code to fix this?

Also nice to know, samsung isn't using smart view for their new tv's. They use smart things now to control the equipment they sell. I only own a TV. But i can check tonight if the smart things app sends some usefull information to the tv.
Before the upgrade to the 1250 firmware, I was able to control my Samsung TV with samsungctl through Domoticz.
Since I've download the new remote_websocket.py file, there isn't error messages anymore when I try a samsungctl command, but I obtain a "permission denied" even if I select "authorise" on my TV.
I guess I have to create a token.txt file somewhere, but I don't know exactly where, and I can't find how to obtain this token... I tried to access to the "wss://@tvip:8002/..." as mentioned sooner with several browser, but I have no response from the TV...
I need some help...
Thanks for reading !

I am working on the issue. I do not own a TV to be able to test with. I am going to set up a slack account for this repo. maybe someone would be willing to forward a few ports so I can have access to the TV. it would greatly speed up the development process not having to do the whole back and forth thing.
adding would be so the IP can be sent to me. if there is anyone willing to do this for me let me know. At the same time I will also check remote button press responses and see if i can possibly leverage the TV to give me some other information/control as well. I am pretty sure I can get volume change notifications from the TV. and possibly channel change and input change. But i need to have access to the TV. after initial access I will request a few more ports be forwarded. but the ports I will not know until i connect with the TV

I’m going to do some testing on my M series In about 40 min when I get home from work :)

here is an invite link for the slack chat. the link is only good for a single day.
https://join.slack.com/t/samsungtvcontrol/shared_invite/enQtNDg5NTgzMDIxMjgyLTg0Y2MzZmY1OGU2NzQ1NjdiNGI5YTkxMjczOTRjMTcyM2MyMTM3YWI5ZTNlNjc5NTcwYTlmNDBhZmM4ZjA4MTY

ok so I wanted to let you all know where I am at.
I still have not gotten a full test result as far as the websocket thing goes.
I have however managed to extend the functionality of the package to include.
getting:
    brightness
    contrast
    color temp
    color
    sharpness
    mute
    volume
    channel
    source
    channel info
    channel list
    source list
    media playback position
    media info
    dtv info
    channel list
    current program information
    detail channel information
    detail program information
    extended information about what options the TV has

all of the below are direct input meaning
you will be able to set the volume to 20 or 30 or 50 or whatever you want directly
setting
    brightness
    contrast
    color temp
    color
    sharpness
    mute
    volume
    channel
    source
    media position

My TV is an older one. But I am sure these will all work with a newer TV a guy I know tested a few of them with success.
It is going to be a very large amount of code that has to be added to support all of the above, I can do it in a dynamic nature which on the back end of it I am. But I am going to hard code most of the interface. this way it is IDE compatible and not a complete mystery how to use.
But I bet you will all like to see volume the current volume or channel data in your favorite HA program eh??
Once I am done with it will be up to you to get the authors of those programs to add that functionality. I am keeping the current API in tact so the package will function as it did before. I am just extending onto it.
I have sorted the issues with the discovery process which is a +

Breaking news : In fact it seems to work properly if I run it as a sudoer ("sudo samsungctl -i --host xxx.xxx.xxx.xxx --port 8002 --method websocket --timeout 10")... Now it remains to make it work through Domoticz... to be continued.

Good news. I'm able again to control the volume through domoticz ... It remains to adapt the keys. For now, I can't turn the tv off. I have a post 2016 ue49mu6105k model ... Do you think I need to edit the interactive.py file?

Yesterday my router died, so had something else to do ;) But i'm online again. Can i test the lastest code? Not sure which one to clone though...

I can confirm though that executing the samsungctl with sudo works! I tried it with the old version, but not yet with the version couple of days ago. After 1 button press it stops working though, have to CTRL+C the program and start it again for the next command.

well it is good to know that it is in fact working to some extent. so we know the solution is viable. just have to work out some of the bugs.
I have the back end for the added controls finished up. I am adding the methods at this point.
from what I am gathering you should be able to do things like change the playing content that is on a USB getting playing content meta data. all kinds of things. there are over 100 different things that can be changed/manipulated.
I am looking for that one single things that will tell me what the firmware version is or something to that effect. it will make the selection of using ssl or not much easier. instead of a try and if it fails then do something else routine.

Did you see my comment on slack? I think I have found a good way to detect to use ssl or not

I did want to post my progress. I now have a plethora of output from the TV. all kinds of goodies.
track_count: 0
media_duration: 0:00:00
media_uri: None
media_metadata: None
playback_device: NETWORK,NONE
record_device: NOT_IMPLEMENTED
write_status: NOT_IMPLEMENTED
state: NO_MEDIA_PRESENT
status: OK
speed: 1
position_info: {
    'absolute_time': '0:00:00',
    'absolute_count':<PHONE_NUMBER>,
    'relative_count':<PHONE_NUMBER>,
    'relative_time': '0:00:00',
    'track_uri': None,
    'track_metadata': None,
    'track_duration': '0:00:00',
    'track_number': 0
}
device_capabilities: [
    'NETWORK,NONE',
    'NOT_IMPLEMENTED',
    'NOT_IMPLEMENTED'
]
brightness: 100
contrast: 100
sharpness: 55
color_temperature: 3
protocol_info: {
    'source': None,
    'sink': [
        'http-get:*:image/jpeg:*',
        'http-get:*:audio/mpeg:*',
        'http-get:*:video/x-msvideo:*',
        'http-get:*:video/x-ms-asf:*',
        'http-get:*:video/x-divx:*',
        'http-get:*:video/x-ms-wmv:*',
        'http-get:*:video/x-mkv:*',
        'http-get:*:video/mp4:*',
        'http-get:*:video/x-avi:*',
        'http-get:*:video/avi:*',
        'http-get:*:video/x-flv:*',
        'http-get:*:video/mpeg:*',
        'http-get:*:video/3gpp:*',
        plus 158 more
    ]
}
x_audio_selection: None
x_video_selection: None
banner_information: None
channel_list: {
    'sort': None,
    'satellite_id': None,
    'channel_list_type': '0x02',
    'version': 19,
    'channel_list_url': 'http://<IP_ADDRESS>:9090/BinaryBlob/3/ChannelList.dat',
    'supported_channels': []
}
source_list: [
    {
        'is_label_editable': False,
        'is_connected': True,
        'id': 0,
        'viewable': True,
        'name': 'TV'
    },
    {
        'viewable': False,
        'name': 'PC',
        'is_label_editable': True,
        'label': 'PC',
        'is_connected': True,
        'id': 67
    },
    {
        'viewable': False,
        'name': 'DLNA',
        'is_label_editable': False,
        'device_name': 'HDHomeRun DMS 131F777B',
        'is_connected': True,
        'id': 23
    },
    {
        'viewable': True,
        'name': 'HDMI1/DVI',
        'is_label_editable': True,
        'label': 'HDMI1/DVI',
        'is_connected': False,
        'id': 71
    },
    {
        'viewable': True,
        'name': 'HDMI2',
        'is_label_editable': True,
        'label': 'HDMI2',
        'is_connected': False,
        'id': 72
    },
    {
        'viewable': True,
        'name': 'HDMI3',
        'is_label_editable': True,
        'label': 'HDMI3',
        'is_connected': False,
        'id': 73
    },
    {
        'viewable': True,
        'name': 'HDMI4',
        'is_label_editable': True,
        'label': 'HDMI4',
        'is_connected': False,
        'id': 74
    },
    {
        'viewable': False,
        'name': 'AV1',
        'is_label_editable': True,
        'label': 'AV1',
        'is_connected': False,
        'id': 55
    },
    {
        'viewable': False,
        'name': 'AV2',
        'is_label_editable': True,
        'label': 'AV2',
        'is_connected': False,
        'id': 56
    },
    {
        'viewable': True,
        'name': 'COMPONENT',
        'is_label_editable': True,
        'label': 'COMPONENT',
        'is_connected': False,
        'id': 63
    },
    {
        'is_label_editable': False,
        'is_connected': False,
        'id': -1,
        'viewable': False,
        'name': 'USB'
    }
]
source: {
    'is_label_editable': False,
    'is_connected': True,
    'id': 0,
    'viewable': True,
    'name': 'TV'
}
channel: {
    'channel_type': 'CATV',
    'program_number': 0,
    'ptc': 6,
    'major': 6,
    'minor': 0
}
program_information_url: http://<IP_ADDRESS>:9090/BinaryBlob/4/CurrentProgInfo.dat
current_time: None
schedule_list_url: http://<IP_ADDRESS>:9090/BinaryBlob/0/ScheduleList.dat
watching_information: {
    'information': None,
    'tv_mode': 'Tuner'
}
mute: False
volume: 50
year: 2011
region: USA
tuner_count: 1
dtv_support: True
pvr_support: False

so now we can get notification if anything on the TV changes. woo yah! I am able to set the channel and volume all the things I stated.

ok here is the version I have been working on.
if you run the example.py file it will run a series of tests and print out a whole mess of data. if you would be willing to copy and paste that data to me I will be able to make sure that everything is working properly. This is still very experimental. it is going to have some hiccups.
https://github.com/kdschlosser/samsungctl/tree/upnp_features

When I try to "git clone" the repositories, I have no UPNP directory, nor example.py file...

Make sure you checkout the correct branch

Thanks @kdschlosser. I've tried git clone but get an error for some reason. I can git clone the main branch fine but just not this one. not sure why? I uninstalled git and reinstalled it but still no joy. This is the error I get:
pi@raspberrypi:~ $ cd /home/pi/Documents/Samsung-check
pi@raspberrypi:~/Documents/Samsung-check $ git clone https://github.com/kdschlosser/samsungctl/tree/upnp_features
Cloning into 'upnp_features'...
fatal: repository 'https://github.com/kdschlosser/samsungctl/tree/upnp_features/' not found

Yeah just tried on my laptop too, the above was on my pi. And I get the same issue.

try
git clone https://github.com/kdschlosser/samsungctl.git
git checkout upnp_features

when i run it i get
Traceback (most recent call last):
File "/Users/tomershemesh/PycharmProjects/samsungctl_branch/samsungctl/example.py", line 41, in
for tv in remote.discover(5):
File "/Users/tomershemesh/PycharmProjects/samsungctl_branch/samsungctl/upnp/discover.py", line 146, in discover
for item in socket.getaddrinfo('', None, socket.AF_INET):
File "/usr/local/Cellar/python3/3.6.1/Frameworks/Python.framework/Versions/3.6/lib/python3.6/socket.py", line 743, in getaddrinfo
for res in _socket.getaddrinfo(host, port, family, type, proto, flags):
socket.gaierror: [Errno 8] nodename nor servname provided, or not known

Still no luck I'm afraid, it can't find the branch:
pi@raspberrypi:~/Documents/Samsung-check $ git clone https://github.com/kdschlosser/samsungctl.git
Cloning into 'samsungctl'...
remote: Enumerating objects: 57, done.
remote: Counting objects: 100% (57/57), done.
remote: Compressing objects: 100% (52/52), done.
remote: Total 483 (delta 21), reused 27 (delta 3), pack-reused 426
Receiving objects: 100% (483/483), 114.06 KiB | 97.00 KiB/s, done.
Resolving deltas: 100% (267/267), done.
pi@raspberrypi:~/Documents/Samsung-check $ git checkout upnp_features
fatal: Not a git repository (or any of the parent directories): .git
pi@raspberrypi:~/Documents/Samsung-check $ sudo git checkout upnp_features
fatal: Not a git repository (or any of the parent directories): .git
pi@raspberrypi:~/Documents/Samsung-check $

Actually looks like I just needed to cd up to the SamsungCtl folder and then switch branch. Ran the discover.py file and get this:
>>> %Run discover.py
Traceback (most recent call last):
  File "/home/pi/Documents/Samsung-check/samsungctl/samsungctl/upnp/discover.py", line 196, in <module>
    for f_device in discover(10):
  File "/home/pi/Documents/Samsung-check/samsungctl/samsungctl/upnp/discover.py", line 146, in discover
    for item in socket.getaddrinfo('', None, socket.AF_INET):
  File "/usr/lib/python3.5/socket.py", line 733, in getaddrinfo
    for res in _socket.getaddrinfo(host, port, family, type, proto, flags):
socket.gaierror: [Errno -2] Name or service not known

ok the error
socket.gaierror: [Errno -2] Name or service not known
is a dns resolver issue.. This can be caused by one of 2 things. and I will see if i can correct on my end.
when i enumerate all of the available IP's in the network stack i pass '', None and the protocol. in this case IPV4
socket.getaddrinfo('', None, socket.AF_INET)

the doct state to pass None and None. but when I do this on Windows the program crashes. I wonder if changing it to None and None on linux will cause it to function properly. If it does then this is actually a bug in Python. it is one that I can band-aide.
so if you change line 146 in upnp/discover.py from
for item in socket.getaddrinfo('', None, socket.AF_INET):

to this
for item in socket.getaddrinfo(None, None, socket.AF_INET):

see if that corrects that issue. If it does not then there is something wrong with the network stack on your Linux installation. specifically the DNS resolver portion of the stack. something wrong with the hosts file possibly.
this error
socket.gaierror: [Errno 8] nodename nor servname provided, or not known

seems to be a MAC specific problem and is a bug in python. It looks as tho I am going to have to find a different mechanism to enumerate the network adapters. This I do not know how to do.
The reason for this is that by design python sockets will always bind to the first network stack in the binding order. when sending out an SSDP packet since it is a broadcast it has to be sent out on that specific adapter. so if you have 2 network interfaces in your coumputer with 2 different network subnets and the TV is located on the network of the address listed second in the binding order the package would never locate it. since I have obtained the IP address of the TV the computers OS will handle binding to the proper address to be able to connect to that IP. but with broadcasts i have to manually bind the address. which is what the getaddrinfo is there for. it is supposed to return all of the IPV4 addressed on the local machine.
Now on the mac it could be the same issue as with linux. so if you want to give it shot follow the instruction above for the linux and see if it works, if it does then it is a simple thing to band-aide.

please be sure to have requests installed if you are not running setup.py as well. there is that single additional requirement that i did add.

this weekend I will spend some time and do a reinstall on my workstation. I need to change out my HDD. I have no more space. Once i do that I will install a VM with Linux on it for testing. I will also dust off my old macbook and hack the latest OSX onto it this way I will be able to test better. at the moment I am limited to testiing in Windows.

I changed the line on 146 to: for item in socket.getaddrinfo(None, None, socket.AF_INET):
However I still get the same error on my pi.
I may be missing something though, I'm not sure what you meant by 'please be sure to have requests installed if you are not running setup.py as well. there is that single additional requirement that i did add.'

requests is a python package the issue you are running into has nothing to do with requests so do not worry about it for the time being. chances are you probably already have the requests python package installed. we can cross that bridge if we get there
I have updated that branch hopefully with the fix.
I do not create any kind of a subprocess and parse the output to get the addresses. I think that is a hack way of going about it but it seems to be the accepted way to do it. so I decided to grab the bull by the cojones and doing directly to the OSX, Linux and Windows API with ctypes to enumerate the local addresses. I am hoping it works.

Thanks Kevin, I checked out the branch again and pulled it but I get this error now. Am I missing some dependencies?:
Python 3.5.3 (/usr/bin/python3)
>>> %cd /home/pi/Documents/Samsung-new/samsungctl/samsungctl/upnp
>>> %Run discover.py
Traceback (most recent call last):
  File "/home/pi/Documents/Samsung-new/samsungctl/samsungctl/upnp/discover.py", line 437, in <module>
    for f_device in discover(10):
  File "/home/pi/Documents/Samsung-new/samsungctl/samsungctl/upnp/discover.py", line 279, in discover
    from . import UPNPTV
SystemError: Parent module '' not loaded, cannot perform relative import
>>>

easiest thing to do would be to install it.
python setup.py install
then use this script to run it
from samsungct import example

and that should be all there is to it.
I may have to update a few other things in it first tho. i will take a look at it in a few minutes

Thanks. I've tried that but get the following issue. I'm probably missing something here:
pi@raspberrypi:~/Documents/Samsung-new/samsungctl $ sudo python3 setup.py install
Traceback (most recent call last):
  File "setup.py", line 5, in <module>
    import samsungctl
  File "/home/pi/Documents/Samsung-new/samsungctl/samsungctl/__init__.py", line 11, in <module>
    from .remote import Remote
  File "/home/pi/Documents/Samsung-new/samsungctl/samsungctl/remote.py", line 2, in <module>
    from .upnp.discover import discover
  File "/home/pi/Documents/Samsung-new/samsungctl/samsungctl/upnp/__init__.py", line 545, in <module>
    from samsungctl.remote_websocket import RemoteWebsocket
  File "/home/pi/Documents/Samsung-new/samsungctl/samsungctl/remote_websocket.py", line 54, in <module>
    class RemoteWebsocket(WebSocketApp):
NameError: name 'WebSocketApp' is not defined
pi@raspberrypi:~/Documents/Samsung-new/samsungctl $

I wonder why it is not installing the requirements.
i will take a look at that bit of it. that is original and I have not changed it at all.

@kdschlosser @fluxdigital
Not sure on this but check the "extras_require" in setup.py.  The websocket-client library is optional as it not needed for "legacy".  Not sure on the exact syntax, but its something like:
pip install samsungctl[websocket]
This will cause the websocket-client library to be installed

ok so I made a new library specifically for scanning the network for UPNP devices. which is the mechanism that is going to open the dorrs to controlling the TV and getting notifications from it as well.
I still need to get the data from a newer TV. I have not gotten that yet. This library will make it easier
https://github.com/kdschlosser/UPNP_Device
it requires requests and also six
pip install requests
pip install six
and place the above package into you site-packages folder.
change the FILEPATH to where ever you can save to. and attach the file to a post. zip it up first tho.
FILEPATH = r'C:\Users\Administrator\Desktop\UPNP.log'

import logging
from UPNP_Devices import discover

with open(FILEPATH, 'w') as f:
    f.write('')

for device in discover(3, logging.DEBUG):
    data = str(device)
    with open(FILEPATH, 'a') as f:
        f.write(data)
        f.flush()

    print(data)

I still need to get the data from a newer TV. I have not gotten that yet. This library will make it easier

Can i help you with something? I have a 2018 model (Q8FN).

you know how to work your way around python??

Hmm i'm not an advanced user, but if it's not too difficult it must succeed.

I've tried the UPNP discovery tool, but it doesn't find my Samsung TV (on the same lan). Is there any way to force the script to a specifik IP address?

I also tried the UPNP tool and also it did not find my Samsung TVs (2017 & 2018 models). Found all my Sonos devices but no TVs.

It could be that the newer TV's do not respond to discovery packets. I am going to add a means to enter the IP of the TV. we can see if this will force a response from it if they are sent directly to the TV. (my router functions in this exact same manner) . Maybe that will instigate a response from the TV.

OK I added the ability to use an IP address to search for in the UPNP_Device library I made.
The FILEPATH is set to create a file on the desktop for a Windows user the filename is UPNP_DEVICE_OUTPUT.log
You can change the FILEPATH to whatever it is you like.
change the TV_IP_ADDRESS to the IP of your TV. and this way we can see if it responds.
from __future__ import print_function
import os
import UPNP_Device
import logging

TV_IP_ADDRESS = '<IP_ADDRESS>'
FILEPATH = r'%USERPROFILE%\Desktop\UPNP_DEVICE_OUTPUT.log'
FILEPATH = os.path.expandvars(FILEPATH)

with open(FILEPATH, 'w') as f:
    for device in UPNP_Device.discover(10, logging.DEBUG):
        data = str(device)
        print(data)
        f.write(data)

I do have some pretty cool news tho.. I will be able to tie in Samsung Soundbars into this library as well.

another thing I have read is that the newer TV's will only respond to UPNP broadcasts using IPV6. so that will be my next endeavor if this update fails to work. but I have other information that contradicts that as well.
This whole process would go a lot faster if I had VPN access to someone's network that the TV is attached to. I can make the updates as I am testing to see if i can get it to respond. Not owning one of these TV's makes it difficult to develop. I own an older one and everything works.

@kdschlosser thanks for your research!
One thought - did you try ST ssdp:all instead of upnp:rootdevice?
M-SEARCH * HTTP/1.1\r\n
HOST: <IP_ADDRESS>:1900\r\n
MAN: "ssdp:discover"\r\n
MX: 1\r\n
ST: ssdp:all\r\n
CONTENT-LENGTH: 0\r\n
\r\n

@kdschlosser do you still need vpn access to a network with a Samsung tv on it?

@kdschlosser  thanks for the work on this. Maybe more hassle then its worth, but there is a TV emulator from the Samsung developer portal and it alludes to having "networking" functionality.
In theory this could help you.....or be a huge PIA
https://developer.samsung.com/tv/develop/getting-started/using-sdk/tv-emulator

i am downloading it now. It does not state that there is UPNP emulation in that. but it doesn't state that their isn't either. so it's a crap shoot.
If iI do not get anywhere with it then the VPN might be the best way to go.

I am goinig to retool the library so that the UPNP is more of an addon then a requirement. this way if it fails then the basic remote functionality will still be available.

@kdschlosser I have Samsung QE55Q7FAM and a VPN server if you are interested.

@kdschlosser Also, not sure if this reference on UPNP is helpful or not:
https://developer.samsung.com/tv/develop/legacy-platform-library/art00030/index
In the header its tagged as "legacy" with reference up to models in 2014

OK this is just stupid.
Their requirements for the Emulator state
https://developer.tizen.org/ko/development/tizen-studio/download/installing-tizen-studio/prerequisites?langredirect=1#emulator
and i quote
CPU | Recommended: Support for Intel VTx (Virtualization Technology)

now is it me of does that say Recommended??????
not Required...
Then on a completely different Samsung page.
https://developer.samsung.com/tv/develop/tools/prerequisites
To use the TV emulator:

Your CPU must support hardware-assisted virtualization:

    For Windows® and macOS, check the Intel® product specifications to make sure that your CPU supports Intel® VT-x.

    For Linux, check the KVM site to make sure that your CPU supports either Intel® VT-x or AMD-V™.

so which is it???
then in a support forum... I find that they state that having the Intel VT-x is required no matter the OS you are running.
now why on Windows is the AMD-V not supported??
they have their heads so far up their asses.
in a support forum they say that the part that is causing the problem can be disabled. but and they simply state disable it in the .conf file. but they do not explain how to go about doing this. if i comment out the line. it crashes. so how do I disable it?? sure as hell beats me.
I do not believe anything they say or their documentation states. I know the newer TV's support UPNP. I have a person that has a 2018 model and it works. He is just not online regularly. so I am not able to work through the issue using him. We have queried the TV using UPNP and it responds. we can change the volume/mute all of that with UPNP.
I am wondering if there is a setting on the TV it's self to disable UPNP and he has it turned on. I know that the smartview application uses UPNP. this is the mechanism that it uses to control the TV.
@KentEkl I am interested in that VPN access. I do not know if you are on the Slack chat or not. here is a link so you can join it. this expires in 24 hours.
https://join.slack.com/t/samsungtvcontrol/shared_invite/enQtNDk4NDUzMzAzODc1LWQwYjEwMWIyYTliN2ZlZWNiNWZkZDZmZTQwYzliNDI0MWJiMDE0OWQxOTkzY2Y0NDA4MDUzNmI4ODNmZGI1YTY
send me a message directly and we can hash out the details on the VPN end of things.
I have to leave for a few hours gotta go and pickup a laptop. I will be back in a few hours. I do not know where about in the world you are. GMT -7:00 is my timezone. I am willing to do this anytime you are available. One thing tho. You need to make sure I will be able to access the internet through the tunnel. it is going to not make my route to the internet non functional. and I will need to have access to resources. I do have most thing available already but in the event I am needing some information I need to have a way to access the information other then disconnecting from the VPN and reconnecting. Tho I can do that if necessary.
send me all of the specific information on the slack chat,

@kdschlosser  I messed around with your code tonight and couldn't get it to discover anything(hard coding IP address, etc.).  I downloaded the intel tool in your screenshot.  It finds the my TV no problem and it looks like the UPNP controls are in fact there.

I tried to use the intel tool to send a SOAP request, but couldn't get anything....however I don't know what I'm doing and I'm sure I didn't have the syntax correct.

see I told you the UPNP works. I am trying to figure out the mechanism that pokes it with a stick to get a response. I need it to tell me the port and so I can grab the structures from it to build the python classes.
I have a really sneaky suspension that if i broadcast the discovery using IPV6 it will respond on IPV4. I have everything set up identical to what the sniffer does except for the IPV6. this is the single thing I have not done. the broadcast packets are identical. the number of them that I broadcast are identical. You can check all of this if you use that UPNP program with the sniffer open. you will see the broadcasts. all except for the IPV6 ones. And I am willing to bet if you do this the TV will not respond.
Using the actions can be a bit tricky. Buy as a little tip. anything that has an "InstanceId" for a parameter you will set that parameter always to 0. this is because the TV can only do a single thing at a time but the UPNP specification is designed so that more then a single thing can be controlled through the same method. an example would be a single controller but multiple screens. and being able to say control the video streams on each of the screens independently. The TV does not have this ability. so that is why it uses a "special use case" InstanceId of 0.
If you would be willing to spend the time you can help me out by compiling the XML for each of the classes and any embedded devices. this can be done by right clicking on an object in the Device Spy and clicking on "view XML" if available. it will then load your browser showing the XML. right click on the browser window and "view page source" copy the XML to a text file. do not reformat it. just plop it into a file the way it is. name the file the same as the object you clicked on in the device spy. you will want to keep some kind of organizational structure. you can do this by making folders of the objects that are a parent of the item you got the xml from and place that item in the folder. if the item has xml and also contains other objects create a folder as the name of the object and also create a file with the same name and place the file inside of that folder.
an example would be
urn:schemas-upnp-org:device:MediaRenderer:1.xml
urn:samsung.com:device:RemoteControlReceiver:1.xml
urn:samsung.com:device:MainTVServer2:1  (folder)
    urn:samsung.com:device:MainTVServer2:1,xml
    urn:samsung.com:device:MainTVAgent:1.xml

This is an actual layout from my TV this way I can create the convenience  methods that will fill in any arbitrary data that the user does not need to have any involvement in.
an example would be what i did for the older TV's when handling sources and channels. With the sources when the user obtains a list of them a list of "Source" instances are returned. they are instances of a clas that I made where a user would be able to do things like.
if not source,is_active:
    source.activate()

or the following will change the name displayed on the TV for the source.
source.label = 'Playstation 4'

it makes it so that the user does not need to deal with any of the SOAP it is all handled behind the scenes. as well handle any incorrect data types that are being sent
so the program will know if the following statement is wrong.
tv.volume = '5'

and when the correct one is used
tv.volume = 5

I have the whole backend already made up. I simply need to nail down the mechanism that gets the TV to respond. and then I can code in the convince  classes.
I will work on the IPV6 stuff today and see where I get.

@kdschlosser  Here are those xml files.  I Think I got it right....if not let me know
Uploading Samsung_Model-UN55MU6300.zip…

it uses that IP address if you do not pass an IP to the call to discover.  or if you pass '<IP_ADDRESS>' to it.
I have made some changes to the UPNP_Device library.
https://github.com/kdschlosser/UPNP_Device/tree/lxml
if you download that one and run
python setup.py install
it will install all required modules as well as the library. then the same script you ran that produced that error. and see what happens.

@kdschlosser Thanks! Getting closer.  Looks like some of the URLs your are processing aren't getting chopped up correctly.
C:\Users\bmurr\PycharmProjects\test_upnp_2\venv\Scripts\python.exe C:/Users/bmurr/PycharmProjects/test_upnp_2/test.py
SSDP: <IP_ADDRESS>
b'M-SEARCH * HTTP/1.1\r\nHOST: <IP_ADDRESS>:1900\r\nMAN: "ssdp:discover"\r\nMX: 1\r\nST: upnp:rootdevice\r\nCONTENT-LENGTH: 0\r\n\r\n'
SSDP: <IP_ADDRESS> - > b'HTTP/1.1 200 OK\r\nCache-Control: max-age=1800\r\nEXT: \r\nLocation: http://<IP_ADDRESS>:49152/0/description.xml\r\nServer: Linux/3.3.8-3.0, UPnP/1.0 DIRECTV JHUPnP/1.0\r\nST: upnp:rootdevice\r\nUSN: uuid:d0545652-5655-5352-5652-023845852682::upnp:rootdevice\r\n\r\n'
SSDP: <IP_ADDRESS> found st: b'upnp:rootdevice'
SSDP: <IP_ADDRESS> found location: b'http://<IP_ADDRESS>:49152/0/description.xml'
SSDP: <IP_ADDRESS> - > b'HTTP/1.1 200 OK\r\nCache-Control: max-age=1800\r\nEXT: \r\nLocation: http://<IP_ADDRESS>:49152/2/description.xml\r\nServer: Linux/3.3.8-3.0, UPnP/1.0 DIRECTV JHUPnP/1.0\r\nST: upnp:rootdevice\r\nUSN: uuid:DIRECTV2PC-Media-Server1_0-RID-023845852682::upnp:rootdevice\r\n\r\n'
SSDP: <IP_ADDRESS> - > b'HTTP/1.1 200 OK\r\nCache-Control: max-age=1800\r\nEXT: \r\nLocation: http://<IP_ADDRESS>:49152/4/description.xml\r\nServer: Linux/3.3.8-3.0, UPnP/1.0 DIRECTV JHUPnP/1.0\r\nST: upnp:rootdevice\r\nUSN: uuid:29bbe0e1-1a6e-47f6-8f8d-6cb56b4ce9f1::upnp:rootdevice\r\n\r\n'
SSDP: <IP_ADDRESS> - > b'HTTP/1.1 200 OK\r\nCache-Control: max-age=1800\r\nEXT: \r\nLocation: http://<IP_ADDRESS>:49152/0/description.xml\r\nServer: Linux/3.3.8-3.0, UPnP/1.0 DIRECTV JHUPnP/1.0\r\nST: upnp:rootdevice\r\nUSN: uuid:d0545652-5655-5352-5652-023845852682::upnp:rootdevice\r\n\r\n'
SSDP: <IP_ADDRESS> - > b'HTTP/1.1 200 OK\r\nCache-Control: max-age=1800\r\nEXT: \r\nLocation: http://<IP_ADDRESS>:49152/2/description.xml\r\nServer: Linux/3.3.8-3.0, UPnP/1.0 DIRECTV JHUPnP/1.0\r\nST: upnp:rootdevice\r\nUSN: uuid:DIRECTV2PC-Media-Server1_0-RID-023845852682::upnp:rootdevice\r\n\r\n'
SSDP: <IP_ADDRESS> - > b'HTTP/1.1 200 OK\r\nCache-Control: max-age=1800\r\nEXT: \r\nLocation: http://<IP_ADDRESS>:49152/4/description.xml\r\nServer: Linux/3.3.8-3.0, UPnP/1.0 DIRECTV JHUPnP/1.0\r\nST: upnp:rootdevice\r\nUSN: uuid:29bbe0e1-1a6e-47f6-8f8d-6cb56b4ce9f1::upnp:rootdevice\r\n\r\n'
SSDP: <IP_ADDRESS> - > b'HTTP/1.1 200 OK\r\nCache-Control: max-age=1800\r\nEXT: \r\nLocation: http://<IP_ADDRESS>:49152/0/description.xml\r\nServer: Linux/3.3.8-3.0, UPnP/1.0 DIRECTV JHUPnP/1.0\r\nST: upnp:rootdevice\r\nUSN: uuid:d0545652-5655-5352-5652-023845852682::upnp:rootdevice\r\n\r\n'
SSDP: <IP_ADDRESS> - > b'HTTP/1.1 200 OK\r\nCache-Control: max-age=1800\r\nEXT: \r\nLocation: http://<IP_ADDRESS>:49152/2/description.xml\r\nServer: Linux/3.3.8-3.0, UPnP/1.0 DIRECTV JHUPnP/1.0\r\nST: upnp:rootdevice\r\nUSN: uuid:DIRECTV2PC-Media-Server1_0-RID-023845852682::upnp:rootdevice\r\n\r\n'
SSDP: <IP_ADDRESS> - > b'HTTP/1.1 200 OK\r\nCache-Control: max-age=1800\r\nEXT: \r\nLocation: http://<IP_ADDRESS>:49152/4/description.xml\r\nServer: Linux/3.3.8-3.0, UPnP/1.0 DIRECTV JHUPnP/1.0\r\nST: upnp:rootdevice\r\nUSN: uuid:29bbe0e1-1a6e-47f6-8f8d-6cb56b4ce9f1::upnp:rootdevice\r\n\r\n'
SSDP: <IP_ADDRESS> - > b'HTTP/1.1 200 OK\r\nCache-Control: max-age=1800\r\nEXT: \r\nLocation: http://<IP_ADDRESS>:49152/0/description.xml\r\nServer: Linux/3.3.8-3.0, UPnP/1.0 DIRECTV JHUPnP/1.0\r\nST: upnp:rootdevice\r\nUSN: uuid:d0545652-5655-5352-5652-023845852682::upnp:rootdevice\r\n\r\n'
SSDP: <IP_ADDRESS> - > b'HTTP/1.1 200 OK\r\nCache-Control: max-age=1800\r\nEXT: \r\nLocation: http://<IP_ADDRESS>:49152/2/description.xml\r\nServer: Linux/3.3.8-3.0, UPnP/1.0 DIRECTV JHUPnP/1.0\r\nST: upnp:rootdevice\r\nUSN: uuid:DIRECTV2PC-Media-Server1_0-RID-023845852682::upnp:rootdevice\r\n\r\n'
SSDP: <IP_ADDRESS> - > b'HTTP/1.1 200 OK\r\nCache-Control: max-age=1800\r\nEXT: \r\nLocation: http://<IP_ADDRESS>:49152/4/description.xml\r\nServer: Linux/3.3.8-3.0, UPnP/1.0 DIRECTV JHUPnP/1.0\r\nST: upnp:rootdevice\r\nUSN: uuid:29bbe0e1-1a6e-47f6-8f8d-6cb56b4ce9f1::upnp:rootdevice\r\n\r\n'
SSDP: <IP_ADDRESS> - > b'HTTP/1.1 200 OK\r\nCache-Control: max-age=1800\r\nEXT: \r\nLocation: http://<IP_ADDRESS>:49152/0/description.xml\r\nServer: Linux/3.3.8-3.0, UPnP/1.0 DIRECTV JHUPnP/1.0\r\nST: upnp:rootdevice\r\nUSN: uuid:d0545652-5655-5352-5652-023845852682::upnp:rootdevice\r\n\r\n'
SSDP: <IP_ADDRESS> - > b'HTTP/1.1 200 OK\r\nCache-Control: max-age=1800\r\nEXT: \r\nLocation: http://<IP_ADDRESS>:49152/2/description.xml\r\nServer: Linux/3.3.8-3.0, UPnP/1.0 DIRECTV JHUPnP/1.0\r\nST: upnp:rootdevice\r\nUSN: uuid:DIRECTV2PC-Media-Server1_0-RID-023845852682::upnp:rootdevice\r\n\r\n'
SSDP: <IP_ADDRESS> - > b'HTTP/1.1 200 OK\r\nCache-Control: max-age=1800\r\nEXT: \r\nLocation: http://<IP_ADDRESS>:49152/4/description.xml\r\nServer: Linux/3.3.8-3.0, UPnP/1.0 DIRECTV JHUPnP/1.0\r\nST: upnp:rootdevice\r\nUSN: uuid:29bbe0e1-1a6e-47f6-8f8d-6cb56b4ce9f1::upnp:rootdevice\r\n\r\n'
SSDP: <IP_ADDRESS> - > b'HTTP/1.1 200 OK\r\nCache-Control: max-age=1800\r\nEXT: \r\nLocation: http://<IP_ADDRESS>:49152/0/description.xml\r\nServer: Linux/3.3.8-3.0, UPnP/1.0 DIRECTV JHUPnP/1.0\r\nST: upnp:rootdevice\r\nUSN: uuid:d0545652-5655-5352-5652-023845852682::upnp:rootdevice\r\n\r\n'
SSDP: <IP_ADDRESS> - > b'HTTP/1.1 200 OK\r\nCache-Control: max-age=1800\r\nEXT: \r\nLocation: http://<IP_ADDRESS>:49152/2/description.xml\r\nServer: Linux/3.3.8-3.0, UPnP/1.0 DIRECTV JHUPnP/1.0\r\nST: upnp:rootdevice\r\nUSN: uuid:DIRECTV2PC-Media-Server1_0-RID-023845852682::upnp:rootdevice\r\n\r\n'
SSDP: <IP_ADDRESS> - > b'HTTP/1.1 200 OK\r\nCache-Control: max-age=1800\r\nEXT: \r\nLocation: http://<IP_ADDRESS>:49152/4/description.xml\r\nServer: Linux/3.3.8-3.0, UPnP/1.0 DIRECTV JHUPnP/1.0\r\nST: upnp:rootdevice\r\nUSN: uuid:29bbe0e1-1a6e-47f6-8f8d-6cb56b4ce9f1::upnp:rootdevice\r\n\r\n'
SSDP: <IP_ADDRESS> - > b'HTTP/1.1 200 OK\r\nCache-Control: max-age=1800\r\nEXT: \r\nLocation: http://<IP_ADDRESS>:49152/0/description.xml\r\nServer: Linux/3.3.8-3.0, UPnP/1.0 DIRECTV JHUPnP/1.0\r\nST: upnp:rootdevice\r\nUSN: uuid:d0545652-5655-5352-5652-023845852682::upnp:rootdevice\r\n\r\n'
SSDP: <IP_ADDRESS> - > b'HTTP/1.1 200 OK\r\nCache-Control: max-age=1800\r\nEXT: \r\nLocation: http://<IP_ADDRESS>:49152/2/description.xml\r\nServer: Linux/3.3.8-3.0, UPnP/1.0 DIRECTV JHUPnP/1.0\r\nST: upnp:rootdevice\r\nUSN: uuid:DIRECTV2PC-Media-Server1_0-RID-023845852682::upnp:rootdevice\r\n\r\n'
SSDP: <IP_ADDRESS> - > b'HTTP/1.1 200 OK\r\nCache-Control: max-age=1800\r\nEXT: \r\nLocation: http://<IP_ADDRESS>:49152/4/description.xml\r\nServer: Linux/3.3.8-3.0, UPnP/1.0 DIRECTV JHUPnP/1.0\r\nST: upnp:rootdevice\r\nUSN: uuid:29bbe0e1-1a6e-47f6-8f8d-6cb56b4ce9f1::upnp:rootdevice\r\n\r\n'
SSDP: <IP_ADDRESS> - > b'HTTP/1.1 200 OK\r\nCache-Control: max-age=1800\r\nEXT: \r\nLocation: http://<IP_ADDRESS>:49152/0/description.xml\r\nServer: Linux/3.3.8-3.0, UPnP/1.0 DIRECTV JHUPnP/1.0\r\nST: upnp:rootdevice\r\nUSN: uuid:d0545652-5655-5352-5652-023845852682::upnp:rootdevice\r\n\r\n'
SSDP: <IP_ADDRESS> - > b'HTTP/1.1 200 OK\r\nCache-Control: max-age=1800\r\nEXT: \r\nLocation: http://<IP_ADDRESS>:49152/2/description.xml\r\nServer: Linux/3.3.8-3.0, UPnP/1.0 DIRECTV JHUPnP/1.0\r\nST: upnp:rootdevice\r\nUSN: uuid:DIRECTV2PC-Media-Server1_0-RID-023845852682::upnp:rootdevice\r\n\r\n'
SSDP: <IP_ADDRESS> - > b'HTTP/1.1 200 OK\r\nCache-Control: max-age=1800\r\nEXT: \r\nLocation: http://<IP_ADDRESS>:49152/4/description.xml\r\nServer: Linux/3.3.8-3.0, UPnP/1.0 DIRECTV JHUPnP/1.0\r\nST: upnp:rootdevice\r\nUSN: uuid:29bbe0e1-1a6e-47f6-8f8d-6cb56b4ce9f1::upnp:rootdevice\r\n\r\n'
SSDP: <IP_ADDRESS> - > b'HTTP/1.1 200 OK\r\nCache-Control: max-age=1800\r\nEXT: \r\nLocation: http://<IP_ADDRESS>:49152/0/description.xml\r\nServer: Linux/3.3.8-3.0, UPnP/1.0 DIRECTV JHUPnP/1.0\r\nST: upnp:rootdevice\r\nUSN: uuid:d0545652-5655-5352-5652-023845852682::upnp:rootdevice\r\n\r\n'
SSDP: <IP_ADDRESS> - > b'HTTP/1.1 200 OK\r\nCache-Control: max-age=1800\r\nEXT: \r\nLocation: http://<IP_ADDRESS>:49152/2/description.xml\r\nServer: Linux/3.3.8-3.0, UPnP/1.0 DIRECTV JHUPnP/1.0\r\nST: upnp:rootdevice\r\nUSN: uuid:DIRECTV2PC-Media-Server1_0-RID-023845852682::upnp:rootdevice\r\n\r\n'
SSDP: <IP_ADDRESS> - > b'HTTP/1.1 200 OK\r\nCache-Control: max-age=1800\r\nEXT: \r\nLocation: http://<IP_ADDRESS>:49152/4/description.xml\r\nServer: Linux/3.3.8-3.0, UPnP/1.0 DIRECTV JHUPnP/1.0\r\nST: upnp:rootdevice\r\nUSN: uuid:29bbe0e1-1a6e-47f6-8f8d-6cb56b4ce9f1::upnp:rootdevice\r\n\r\n'
SSDP: <IP_ADDRESS> - > b'HTTP/1.1 200 OK\r\nCache-Control: max-age=1800\r\nEXT: \r\nLocation: http://<IP_ADDRESS>:49152/0/description.xml\r\nServer: Linux/3.3.8-3.0, UPnP/1.0 DIRECTV JHUPnP/1.0\r\nST: upnp:rootdevice\r\nUSN: uuid:d0545652-5655-5352-5652-023845852682::upnp:rootdevice\r\n\r\n'
SSDP: <IP_ADDRESS> - > b'HTTP/1.1 200 OK\r\nCache-Control: max-age=1800\r\nEXT: \r\nLocation: http://<IP_ADDRESS>:49152/2/description.xml\r\nServer: Linux/3.3.8-3.0, UPnP/1.0 DIRECTV JHUPnP/1.0\r\nST: upnp:rootdevice\r\nUSN: uuid:DIRECTV2PC-Media-Server1_0-RID-023845852682::upnp:rootdevice\r\n\r\n'
SSDP: <IP_ADDRESS> - > b'HTTP/1.1 200 OK\r\nCache-Control: max-age=1800\r\nEXT: \r\nLocation: http://<IP_ADDRESS>:49152/4/description.xml\r\nServer: Linux/3.3.8-3.0, UPnP/1.0 DIRECTV JHUPnP/1.0\r\nST: upnp:rootdevice\r\nUSN: uuid:29bbe0e1-1a6e-47f6-8f8d-6cb56b4ce9f1::upnp:rootdevice\r\n\r\n'
SSDP: <IP_ADDRESS> - > b'HTTP/1.1 200 OK\r\nDate: Sat, Dec  8 18:34:10 2018\r\nCache-Control: max-age=1800\r\nExt: \r\nServer: Linux/2.6.22 UPnP/1.1 JetHeadInc/1\r\nLOCATION: http://<IP_ADDRESS>:63444/upnp/xml/devices/ManageableDevice1.xml\r\nST: upnp:rootdevice\r\nUSN: uuid:ManageableDevice-08_EB_74_19_61_13::upnp:rootdevice\r\n\r\n'
SSDP: <IP_ADDRESS> - > b'HTTP/1.1 200 OK\r\nCACHE-CONTROL: max-age=120\r\nST: upnp:rootdevice\r\nUSN: uuid:14194637-60e7-4ef9-b3f3-ef9c49947396::upnp:rootdevice\r\nEXT:\r\nSERVER: Debian/wheezy UPnP/1.1 MiniUPnPd/2.0\r\nLOCATION: http://<IP_ADDRESS>:53583/rootDesc.xml\r\nOPT: "http://schemas.upnp.org/upnp/1/0/"; ns=01\r\n01-NLS:<PHONE_NUMBER>\r\nBOOTID.UPNP.ORG:<PHONE_NUMBER>\r\nCONFIGID.UPNP.ORG: 1337\r\n\r\n'
SSDP: <IP_ADDRESS> - > b'HTTP/1.1 200 OK\r\nCACHE-CONTROL: max-age=120\r\nST: upnp:rootdevice\r\nUSN: uuid:14194637-60e7-4ef9-b3f3-ef9c49947396::upnp:rootdevice\r\nEXT:\r\nSERVER: Debian/wheezy UPnP/1.1 MiniUPnPd/2.0\r\nLOCATION: http://<IP_ADDRESS>:53583/rootDesc.xml\r\nOPT: "http://schemas.upnp.org/upnp/1/0/"; ns=01\r\n01-NLS:<PHONE_NUMBER>\r\nBOOTID.UPNP.ORG:<PHONE_NUMBER>\r\nCONFIGID.UPNP.ORG: 1337\r\n\r\n'
SSDP: <IP_ADDRESS> - > b'HTTP/1.1 200 OK\r\nCACHE-CONTROL: max-age=120\r\nST: upnp:rootdevice\r\nUSN: uuid:14194637-60e7-4ef9-b3f3-ef9c49947396::upnp:rootdevice\r\nEXT:\r\nSERVER: Debian/wheezy UPnP/1.1 MiniUPnPd/2.0\r\nLOCATION: http://<IP_ADDRESS>:53583/rootDesc.xml\r\nOPT: "http://schemas.upnp.org/upnp/1/0/"; ns=01\r\n01-NLS:<PHONE_NUMBER>\r\nBOOTID.UPNP.ORG:<PHONE_NUMBER>\r\nCONFIGID.UPNP.ORG: 1337\r\n\r\n'
SSDP: <IP_ADDRESS> - > b'HTTP/1.1 200 OK\r\nCACHE-CONTROL: max-age=120\r\nST: upnp:rootdevice\r\nUSN: uuid:14194637-60e7-4ef9-b3f3-ef9c49947396::upnp:rootdevice\r\nEXT:\r\nSERVER: Debian/wheezy UPnP/1.1 MiniUPnPd/2.0\r\nLOCATION: http://<IP_ADDRESS>:53583/rootDesc.xml\r\nOPT: "http://schemas.upnp.org/upnp/1/0/"; ns=01\r\n01-NLS:<PHONE_NUMBER>\r\nBOOTID.UPNP.ORG:<PHONE_NUMBER>\r\nCONFIGID.UPNP.ORG: 1337\r\n\r\n'
SSDP: <IP_ADDRESS> - > b'HTTP/1.1 200 OK\r\nCACHE-CONTROL: max-age=120\r\nST: upnp:rootdevice\r\nUSN: uuid:14194637-60e7-4ef9-b3f3-ef9c49947396::upnp:rootdevice\r\nEXT:\r\nSERVER: Debian/wheezy UPnP/1.1 MiniUPnPd/2.0\r\nLOCATION: http://<IP_ADDRESS>:53583/rootDesc.xml\r\nOPT: "http://schemas.upnp.org/upnp/1/0/"; ns=01\r\n01-NLS:<PHONE_NUMBER>\r\nBOOTID.UPNP.ORG:<PHONE_NUMBER>\r\nCONFIGID.UPNP.ORG: 1337\r\n\r\n'
SSDP: <IP_ADDRESS> - > b'HTTP/1.1 200 OK\r\nDate: Sat, Dec  8 18:33:21 2018\r\nCache-Control: max-age=1800\r\nExt: \r\nServer: Linux/2.6.22 UPnP/1.1 JetHeadInc/1\r\nLOCATION: http://<IP_ADDRESS>:63444/upnp/xml/devices/ManageableDevice1.xml\r\nST: upnp:rootdevice\r\nUSN: uuid:ManageableDevice-08_EB_74_86_88_0D::upnp:rootdevice\r\n\r\n'
SSDP: <IP_ADDRESS> - > b'HTTP/1.1 200 OK\r\nDate: Sat, Dec  8 18:34:10 2018\r\nCache-Control: max-age=1800\r\nExt: \r\nServer: Linux/2.6.22 UPnP/1.1 JetHeadInc/1\r\nLOCATION: http://<IP_ADDRESS>:63444/upnp/xml/devices/ManageableDevice1.xml\r\nST: upnp:rootdevice\r\nUSN: uuid:ManageableDevice-08_EB_74_19_61_13::upnp:rootdevice\r\n\r\n'
SSDP: <IP_ADDRESS> - > b'HTTP/1.1 200 OK\r\nCACHE-CONTROL: max-age=1800\r\nDATE: Sat, 08 Dec 2018 18:34:14 GMT\r\nEXT: \r\nLOCATION: http://<IP_ADDRESS>:9110/ip_control\r\nSERVER: Samsung-Linux/4.1, UPnP/1.0, Samsung_UPnP_SDK/1.0\r\nST: upnp:rootdevice\r\nUSN: uuid:b5a38c37-2489-40df-97c3-93b4b157b3d1::upnp:rootdevice\r\nContent-Length: 0\r\nBOOTID.UPNP.ORG: 30\r\n\r\n'
SSDP: <IP_ADDRESS> - > b'HTTP/1.1 200 OK\r\nCACHE-CONTROL: max-age=1800\r\nDATE: Sat, 08 Dec 2018 18:34:14 GMT\r\nEXT: \r\nLOCATION: http://<IP_ADDRESS>:7676/rcr/\r\nSERVER: Samsung-Linux/4.1, UPnP/1.0, Samsung_UPnP_SDK/1.0\r\nST: upnp:rootdevice\r\nUSN: uuid:68f9ea62-6e70-443f-bdd5-f9736516a675::upnp:rootdevice\r\nContent-Length: 0\r\nBOOTID.UPNP.ORG: 43\r\n\r\n'
SSDP: <IP_ADDRESS> - > b'HTTP/1.1 200 OK\r\nCACHE-CONTROL: max-age=1800\r\nDATE: Sat, 08 Dec 2018 18:34:14 GMT\r\nEXT: \r\nLOCATION: http://<IP_ADDRESS>:7676/rcr/\r\nSERVER: Samsung-Linux/4.1, UPnP/1.0, Samsung_UPnP_SDK/1.0\r\nST: upnp:rootdevice\r\nUSN: uuid:68f9ea62-6e70-443f-bdd5-f9736516a675::upnp:rootdevice\r\nContent-Length: 0\r\nBOOTID.UPNP.ORG: 43\r\n\r\n'
SSDP: <IP_ADDRESS> - > b'HTTP/1.1 200 OK\r\nCACHE-CONTROL: max-age=1800\r\nDATE: Sat, 08 Dec 2018 18:34:14 GMT\r\nEXT: \r\nLOCATION: http://<IP_ADDRESS>:9197/dmr\r\nSERVER: Samsung-Linux/4.1, UPnP/1.0, Samsung_UPnP_SDK/1.0\r\nST: upnp:rootdevice\r\nUSN: uuid:4d5136b9-8985-43dd-b768-bb8b368c1968::upnp:rootdevice\r\nContent-Length: 0\r\nBOOTID.UPNP.ORG: 30\r\n\r\n'
SSDP: <IP_ADDRESS> - > b'HTTP/1.1 200 OK\r\nCACHE-CONTROL: max-age=1800\r\nDATE: Sat, 08 Dec 2018 18:34:14 GMT\r\nEXT: \r\nLOCATION: http://<IP_ADDRESS>:9110/ip_control\r\nSERVER: Samsung-Linux/4.1, UPnP/1.0, Samsung_UPnP_SDK/1.0\r\nST: upnp:rootdevice\r\nUSN: uuid:b5a38c37-2489-40df-97c3-93b4b157b3d1::upnp:rootdevice\r\nContent-Length: 0\r\nBOOTID.UPNP.ORG: 30\r\n\r\n'
SSDP: <IP_ADDRESS> - > b'HTTP/1.1 200 OK\r\nCACHE-CONTROL: max-age=1800\r\nDATE: Sat, 08 Dec 2018 18:34:14 GMT\r\nEXT: \r\nLOCATION: http://<IP_ADDRESS>:7676/rcr/\r\nSERVER: Samsung-Linux/4.1, UPnP/1.0, Samsung_UPnP_SDK/1.0\r\nST: upnp:rootdevice\r\nUSN: uuid:68f9ea62-6e70-443f-bdd5-f9736516a675::upnp:rootdevice\r\nContent-Length: 0\r\nBOOTID.UPNP.ORG: 43\r\n\r\n'
SSDP: <IP_ADDRESS> - > b'HTTP/1.1 200 OK\r\nCACHE-CONTROL: max-age=1800\r\nDATE: Sat, 08 Dec 2018 18:34:14 GMT\r\nEXT: \r\nLOCATION: http://<IP_ADDRESS>:9197/dmr\r\nSERVER: Samsung-Linux/4.1, UPnP/1.0, Samsung_UPnP_SDK/1.0\r\nST: upnp:rootdevice\r\nUSN: uuid:4d5136b9-8985-43dd-b768-bb8b368c1968::upnp:rootdevice\r\nContent-Length: 0\r\nBOOTID.UPNP.ORG: 30\r\n\r\n'
SSDP: <IP_ADDRESS> - > b'HTTP/1.1 200 OK\r\nCACHE-CONTROL: max-age=1800\r\nDATE: Sat, 08 Dec 2018 18:34:14 GMT\r\nEXT: \r\nLOCATION: http://<IP_ADDRESS>:9110/ip_control\r\nSERVER: Samsung-Linux/4.1, UPnP/1.0, Samsung_UPnP_SDK/1.0\r\nST: upnp:rootdevice\r\nUSN: uuid:b5a38c37-2489-40df-97c3-93b4b157b3d1::upnp:rootdevice\r\nContent-Length: 0\r\nBOOTID.UPNP.ORG: 30\r\n\r\n'
SSDP: <IP_ADDRESS> - > b'HTTP/1.1 200 OK\r\nCACHE-CONTROL: max-age=1800\r\nDATE: Sat, 08 Dec 2018 18:34:14 GMT\r\nEXT: \r\nLOCATION: http://<IP_ADDRESS>:7676/rcr/\r\nSERVER: Samsung-Linux/4.1, UPnP/1.0, Samsung_UPnP_SDK/1.0\r\nST: upnp:rootdevice\r\nUSN: uuid:68f9ea62-6e70-443f-bdd5-f9736516a675::upnp:rootdevice\r\nContent-Length: 0\r\nBOOTID.UPNP.ORG: 43\r\n\r\n'
SSDP: <IP_ADDRESS> - > b'HTTP/1.1 200 OK\r\nCACHE-CONTROL: max-age=1800\r\nDATE: Sat, 08 Dec 2018 18:34:14 GMT\r\nEXT: \r\nLOCATION: http://<IP_ADDRESS>:9197/dmr\r\nSERVER: Samsung-Linux/4.1, UPnP/1.0, Samsung_UPnP_SDK/1.0\r\nST: upnp:rootdevice\r\nUSN: uuid:4d5136b9-8985-43dd-b768-bb8b368c1968::upnp:rootdevice\r\nContent-Length: 0\r\nBOOTID.UPNP.ORG: 30\r\n\r\n'
SSDP: <IP_ADDRESS> - > b'HTTP/1.1 200 OK\r\nCACHE-CONTROL: max-age=1800\r\nDATE: Sat, 08 Dec 2018 18:34:14 GMT\r\nEXT: \r\nLOCATION: http://<IP_ADDRESS>:9110/ip_control\r\nSERVER: Samsung-Linux/4.1, UPnP/1.0, Samsung_UPnP_SDK/1.0\r\nST: upnp:rootdevice\r\nUSN: uuid:b5a38c37-2489-40df-97c3-93b4b157b3d1::upnp:rootdevice\r\nContent-Length: 0\r\nBOOTID.UPNP.ORG: 30\r\n\r\n'
SSDP: <IP_ADDRESS> - > b'HTTP/1.1 200 OK\r\nCACHE-CONTROL: max-age=1800\r\nDATE: Sat, 08 Dec 2018 18:34:14 GMT\r\nEXT: \r\nLOCATION: http://<IP_ADDRESS>:9110/ip_control\r\nSERVER: Samsung-Linux/4.1, UPnP/1.0, Samsung_UPnP_SDK/1.0\r\nST: upnp:rootdevice\r\nUSN: uuid:b5a38c37-2489-40df-97c3-93b4b157b3d1::upnp:rootdevice\r\nContent-Length: 0\r\nBOOTID.UPNP.ORG: 30\r\n\r\n'
SSDP: <IP_ADDRESS> - > b'HTTP/1.1 200 OK\r\nCACHE-CONTROL: max-age=1800\r\nDATE: Sat, 08 Dec 2018 18:34:14 GMT\r\nEXT: \r\nLOCATION: http://<IP_ADDRESS>:9197/dmr\r\nSERVER: Samsung-Linux/4.1, UPnP/1.0, Samsung_UPnP_SDK/1.0\r\nST: upnp:rootdevice\r\nUSN: uuid:4d5136b9-8985-43dd-b768-bb8b368c1968::upnp:rootdevice\r\nContent-Length: 0\r\nBOOTID.UPNP.ORG: 30\r\n\r\n'
SSDP: <IP_ADDRESS> - > b'HTTP/1.1 200 OK\r\nCACHE-CONTROL: max-age=1800\r\nDATE: Sat, 08 Dec 2018 18:34:14 GMT\r\nEXT: \r\nLOCATION: http://<IP_ADDRESS>:9119/screen_sharing\r\nSERVER: Samsung-Linux/4.1, UPnP/1.0, Samsung_UPnP_SDK/1.0\r\nST: upnp:rootdevice\r\nUSN: uuid:4ddef41f-7d3a-4875-a15d-2e3eba5f2984::upnp:rootdevice\r\nContent-Length: 0\r\nBOOTID.UPNP.ORG: 34\r\n\r\n'
SSDP: <IP_ADDRESS> - > b'HTTP/1.1 200 OK\r\nCACHE-CONTROL: max-age=1800\r\nDATE: Sat, 08 Dec 2018 18:34:14 GMT\r\nEXT: \r\nLOCATION: http://<IP_ADDRESS>:9119/screen_sharing\r\nSERVER: Samsung-Linux/4.1, UPnP/1.0, Samsung_UPnP_SDK/1.0\r\nST: upnp:rootdevice\r\nUSN: uuid:4ddef41f-7d3a-4875-a15d-2e3eba5f2984::upnp:rootdevice\r\nContent-Length: 0\r\nBOOTID.UPNP.ORG: 34\r\n\r\n'
SSDP: <IP_ADDRESS> - > b'HTTP/1.1 200 OK\r\nCACHE-CONTROL: max-age=1800\r\nDATE: Sat, 08 Dec 2018 18:34:14 GMT\r\nEXT: \r\nLOCATION: http://<IP_ADDRESS>:9119/screen_sharing\r\nSERVER: Samsung-Linux/4.1, UPnP/1.0, Samsung_UPnP_SDK/1.0\r\nST: upnp:rootdevice\r\nUSN: uuid:4ddef41f-7d3a-4875-a15d-2e3eba5f2984::upnp:rootdevice\r\nContent-Length: 0\r\nBOOTID.UPNP.ORG: 34\r\n\r\n'
SSDP: <IP_ADDRESS> - > b'HTTP/1.1 200 OK\r\nCACHE-CONTROL: max-age=1800\r\nDATE: Sat, 08 Dec 2018 18:34:14 GMT\r\nEXT: \r\nLOCATION: http://<IP_ADDRESS>:7676/rcr/\r\nSERVER: Samsung-Linux/4.1, UPnP/1.0, Samsung_UPnP_SDK/1.0\r\nST: upnp:rootdevice\r\nUSN: uuid:68f9ea62-6e70-443f-bdd5-f9736516a675::upnp:rootdevice\r\nContent-Length: 0\r\nBOOTID.UPNP.ORG: 43\r\n\r\n'
SSDP: <IP_ADDRESS> - > b'HTTP/1.1 200 OK\r\nCACHE-CONTROL: max-age=1800\r\nDATE: Sat, 08 Dec 2018 18:34:14 GMT\r\nEXT: \r\nLOCATION: http://<IP_ADDRESS>:9119/screen_sharing\r\nSERVER: Samsung-Linux/4.1, UPnP/1.0, Samsung_UPnP_SDK/1.0\r\nST: upnp:rootdevice\r\nUSN: uuid:4ddef41f-7d3a-4875-a15d-2e3eba5f2984::upnp:rootdevice\r\nContent-Length: 0\r\nBOOTID.UPNP.ORG: 34\r\n\r\n'
SSDP: <IP_ADDRESS> - > b'HTTP/1.1 200 OK\r\nCACHE-CONTROL: max-age=1800\r\nDATE: Sat, 08 Dec 2018 18:34:14 GMT\r\nEXT: \r\nLOCATION: http://<IP_ADDRESS>:9119/screen_sharing\r\nSERVER: Samsung-Linux/4.1, UPnP/1.0, Samsung_UPnP_SDK/1.0\r\nST: upnp:rootdevice\r\nUSN: uuid:4ddef41f-7d3a-4875-a15d-2e3eba5f2984::upnp:rootdevice\r\nContent-Length: 0\r\nBOOTID.UPNP.ORG: 34\r\n\r\n'
SSDP: <IP_ADDRESS> - > b'HTTP/1.1 200 OK\r\nCACHE-CONTROL: max-age=1800\r\nDATE: Sat, 08 Dec 2018 18:34:14 GMT\r\nEXT: \r\nLOCATION: http://<IP_ADDRESS>:9197/dmr\r\nSERVER: Samsung-Linux/4.1, UPnP/1.0, Samsung_UPnP_SDK/1.0\r\nST: upnp:rootdevice\r\nUSN: uuid:4d5136b9-8985-43dd-b768-bb8b368c1968::upnp:rootdevice\r\nContent-Length: 0\r\nBOOTID.UPNP.ORG: 30\r\n\r\n'
SSDP: <IP_ADDRESS> - > b'HTTP/1.1 200 OK\r\nCACHE-CONTROL: max-age=1800\r\nDATE: Sat, 08 Dec 2018 18:34:14 GMT\r\nEXT: \r\nLOCATION: http://<IP_ADDRESS>:7678/nservice/\r\nSERVER: Samsung-Linux/4.1, UPnP/1.0, Samsung_UPnP_SDK/1.0\r\nST: upnp:rootdevice\r\nUSN: uuid:5acf18e6-d1bd-4411-8d8e-e0e889fce44e::upnp:rootdevice\r\nContent-Length: 0\r\nBOOTID.UPNP.ORG: 43\r\n\r\n'
SSDP: <IP_ADDRESS> - > b'HTTP/1.1 200 OK\r\nCACHE-CONTROL: max-age=1800\r\nDATE: Sat, 08 Dec 2018 18:34:14 GMT\r\nEXT: \r\nLOCATION: http://<IP_ADDRESS>:7678/nservice/\r\nSERVER: Samsung-Linux/4.1, UPnP/1.0, Samsung_UPnP_SDK/1.0\r\nST: upnp:rootdevice\r\nUSN: uuid:5acf18e6-d1bd-4411-8d8e-e0e889fce44e::upnp:rootdevice\r\nContent-Length: 0\r\nBOOTID.UPNP.ORG: 43\r\n\r\n'
SSDP: <IP_ADDRESS> - > b'HTTP/1.1 200 OK\r\nCACHE-CONTROL: max-age=1800\r\nDATE: Sat, 08 Dec 2018 18:34:14 GMT\r\nEXT: \r\nLOCATION: http://<IP_ADDRESS>:7678/nservice/\r\nSERVER: Samsung-Linux/4.1, UPnP/1.0, Samsung_UPnP_SDK/1.0\r\nST: upnp:rootdevice\r\nUSN: uuid:5acf18e6-d1bd-4411-8d8e-e0e889fce44e::upnp:rootdevice\r\nContent-Length: 0\r\nBOOTID.UPNP.ORG: 43\r\n\r\n'
SSDP: <IP_ADDRESS> - > b'HTTP/1.1 200 OK\r\nCACHE-CONTROL: max-age=1800\r\nDATE: Sat, 08 Dec 2018 18:34:14 GMT\r\nEXT: \r\nLOCATION: http://<IP_ADDRESS>:7678/nservice/\r\nSERVER: Samsung-Linux/4.1, UPnP/1.0, Samsung_UPnP_SDK/1.0\r\nST: upnp:rootdevice\r\nUSN: uuid:5acf18e6-d1bd-4411-8d8e-e0e889fce44e::upnp:rootdevice\r\nContent-Length: 0\r\nBOOTID.UPNP.ORG: 43\r\n\r\n'
SSDP: <IP_ADDRESS> - > b'HTTP/1.1 200 OK\r\nCACHE-CONTROL: max-age=1800\r\nDATE: Sat, 08 Dec 2018 18:34:14 GMT\r\nEXT: \r\nLOCATION: http://<IP_ADDRESS>:7678/nservice/\r\nSERVER: Samsung-Linux/4.1, UPnP/1.0, Samsung_UPnP_SDK/1.0\r\nST: upnp:rootdevice\r\nUSN: uuid:5acf18e6-d1bd-4411-8d8e-e0e889fce44e::upnp:rootdevice\r\nContent-Length: 0\r\nBOOTID.UPNP.ORG: 43\r\n\r\n'
SSDP: <IP_ADDRESS> - > b'HTTP/1.1 200 OK\r\nDate: Sat, Dec  8 18:34:10 2018\r\nCache-Control: max-age=1800\r\nExt: \r\nServer: Linux/2.6.22 UPnP/1.1 JetHeadInc/1\r\nLOCATION: http://<IP_ADDRESS>:63444/upnp/xml/devices/ManageableDevice1.xml\r\nST: upnp:rootdevice\r\nUSN: uuid:ManageableDevice-08_EB_74_19_61_13::upnp:rootdevice\r\n\r\n'
SSDP: <IP_ADDRESS> - > b'HTTP/1.1 200 OK\r\nDate: Sat, Dec  8 18:33:21 2018\r\nCache-Control: max-age=1800\r\nExt: \r\nServer: Linux/2.6.22 UPnP/1.1 JetHeadInc/1\r\nLOCATION: http://<IP_ADDRESS>:63444/upnp/xml/devices/ManageableDevice1.xml\r\nST: upnp:rootdevice\r\nUSN: uuid:ManageableDevice-08_EB_74_86_88_0D::upnp:rootdevice\r\n\r\n'
SSDP: <IP_ADDRESS> - > b'HTTP/1.1 200 OK\r\nDate: Sat, Dec  8 18:34:10 2018\r\nCache-Control: max-age=1800\r\nExt: \r\nServer: Linux/2.6.22 UPnP/1.1 JetHeadInc/1\r\nLOCATION: http://<IP_ADDRESS>:63444/upnp/xml/devices/ManageableDevice1.xml\r\nST: upnp:rootdevice\r\nUSN: uuid:ManageableDevice-08_EB_74_19_61_13::upnp:rootdevice\r\n\r\n'
SSDP: <IP_ADDRESS> - > b'HTTP/1.1 200 OK\r\nDate: Sat, Dec  8 18:34:10 2018\r\nCache-Control: max-age=1800\r\nExt: \r\nServer: Linux/2.6.22 UPnP/1.1 JetHeadInc/1\r\nLOCATION: http://<IP_ADDRESS>:63444/upnp/xml/devices/ManageableDevice1.xml\r\nST: upnp:rootdevice\r\nUSN: uuid:ManageableDevice-08_EB_74_19_61_13::upnp:rootdevice\r\n\r\n'
SSDP: <IP_ADDRESS> - > b'HTTP/1.1 200 OK\r\nDate: Sat, Dec  8 18:33:21 2018\r\nCache-Control: max-age=1800\r\nExt: \r\nServer: Linux/2.6.22 UPnP/1.1 JetHeadInc/1\r\nLOCATION: http://<IP_ADDRESS>:63444/upnp/xml/devices/ManageableDevice1.xml\r\nST: upnp:rootdevice\r\nUSN: uuid:ManageableDevice-08_EB_74_86_88_0D::upnp:rootdevice\r\n\r\n'
SSDP: <IP_ADDRESS> - > b'HTTP/1.1 200 OK\r\nDate: Sat, Dec  8 18:33:21 2018\r\nCache-Control: max-age=1800\r\nExt: \r\nServer: Linux/2.6.22 UPnP/1.1 JetHeadInc/1\r\nLOCATION: http://<IP_ADDRESS>:63444/upnp/xml/devices/ManageableDevice1.xml\r\nST: upnp:rootdevice\r\nUSN: uuid:ManageableDevice-08_EB_74_86_88_0D::upnp:rootdevice\r\n\r\n'
SSDP: <IP_ADDRESS> - > b'HTTP/1.1 200 OK\r\nDate: Sat, Dec  8 18:33:21 2018\r\nCache-Control: max-age=1800\r\nExt: \r\nServer: Linux/2.6.22 UPnP/1.1 JetHeadInc/1\r\nLOCATION: http://<IP_ADDRESS>:63444/upnp/xml/devices/ManageableDevice1.xml\r\nST: upnp:rootdevice\r\nUSN: uuid:ManageableDevice-08_EB_74_86_88_0D::upnp:rootdevice\r\n\r\n'
SSDP: <IP_ADDRESS> creating UPNPObject instance
C:\Users\bmurr\PycharmProjects\test_upnp_2\UPNP_Device\upnp_class.py:35: FutureWarning: The behavior of this method will change in future versions. Use specific 'len(elem)' or 'elem is not None' test instead.
  services = node.find('serviceList') or []
C:\Users\bmurr\PycharmProjects\test_upnp_2\UPNP_Device\upnp_class.py:36: FutureWarning: The behavior of this method will change in future versions. Use specific 'len(elem)' or 'elem is not None' test instead.
  devices = node.find('deviceList') or []
C:\Users\bmurr\PycharmProjects\test_upnp_2\UPNP_Device\service.py:31: FutureWarning: The behavior of this method will change in future versions. Use specific 'len(elem)' or 'elem is not None' test instead.
  icons = node.find('iconList') or []
C:\Users\bmurr\PycharmProjects\test_upnp_2\UPNP_Device\service.py:43: FutureWarning: The behavior of this method will change in future versions. Use specific 'len(elem)' or 'elem is not None' test instead.
  actions = root.find('actionList') or []
C:\Users\bmurr\PycharmProjects\test_upnp_2\UPNP_Device\service.py:44: FutureWarning: The behavior of this method will change in future versions. Use specific 'len(elem)' or 'elem is not None' test instead.
  state_variables = root.find('serviceStateTable') or []
C:\Users\bmurr\PycharmProjects\test_upnp_2\UPNP_Device\embedded_device.py:23: FutureWarning: The behavior of this method will change in future versions. Use specific 'len(elem)' or 'elem is not None' test instead.
  icons = node.find('iconList') or []
C:\Users\bmurr\PycharmProjects\test_upnp_2\UPNP_Device\embedded_device.py:24: FutureWarning: The behavior of this method will change in future versions. Use specific 'len(elem)' or 'elem is not None' test instead.
  services = node.find('serviceList') or []
Exception in thread Thread-1:
Traceback (most recent call last):
  File "C:\Users\bmurr\PycharmProjects\test_upnp_2\venv\lib\site-packages\requests\models.py", line 379, in prepare_url
    scheme, auth, host, port, path, query, fragment = parse_url(url)
  File "C:\Users\bmurr\PycharmProjects\test_upnp_2\venv\lib\site-packages\urllib3\util\url.py", line 199, in parse_url
    raise LocationParseError(url)
urllib3.exceptions.LocationParseError: Failed to parse: <IP_ADDRESS>:49152http:

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "C:\Users\bmurr\AppData\Local\Programs\Python\Python35\lib\threading.py", line 923, in _bootstrap_inner
    self.run()
  File "C:\Users\bmurr\AppData\Local\Programs\Python\Python35\lib\threading.py", line 871, in run
    self._target(*self._args, **self._kwargs)
  File "C:\Users\bmurr\PycharmProjects\test_upnp_2\UPNP_Device\discover.py", line 425, in found_thread
    found_classes.append(UPNPObject(addr, classes))
  File "C:\Users\bmurr\PycharmProjects\test_upnp_2\UPNP_Device\instance_singleton.py", line 14, in __call__
    super(InstanceSingleton, cls).__call__(ip, classes)
  File "C:\Users\bmurr\PycharmProjects\test_upnp_2\UPNP_Device\upnp_class.py", line 66, in __init__
    device = EmbeddedDevice(url, node=device, parent=self)
  File "C:\Users\bmurr\PycharmProjects\test_upnp_2\UPNP_Device\embedded_device.py", line 48, in __init__
    service = Service(self, url, scpdurl, service_type, control_url)
  File "C:\Users\bmurr\PycharmProjects\test_upnp_2\UPNP_Device\service.py", line 38, in __init__
    response = requests.get(url + location)
  File "C:\Users\bmurr\PycharmProjects\test_upnp_2\venv\lib\site-packages\requests\api.py", line 75, in get
    return request('get', url, params=params, **kwargs)
  File "C:\Users\bmurr\PycharmProjects\test_upnp_2\venv\lib\site-packages\requests\api.py", line 60, in request
    return session.request(method=method, url=url, **kwargs)
  File "C:\Users\bmurr\PycharmProjects\test_upnp_2\venv\lib\site-packages\requests\sessions.py", line 519, in request
    prep = self.prepare_request(req)
  File "C:\Users\bmurr\PycharmProjects\test_upnp_2\venv\lib\site-packages\requests\sessions.py", line 462, in prepare_request
    hooks=merge_hooks(request.hooks, self.hooks),
  File "C:\Users\bmurr\PycharmProjects\test_upnp_2\venv\lib\site-packages\requests\models.py", line 313, in prepare
    self.prepare_url(url, params)
  File "C:\Users\bmurr\PycharmProjects\test_upnp_2\venv\lib\site-packages\requests\models.py", line 381, in prepare_url
    raise InvalidURL(*e.args)
requests.exceptions.InvalidURL: Failed to parse: <IP_ADDRESS>:49152http:

that it does. so we are a step further.

OK give it a shot now. I think i fixed the issue with the URL and there were a couple other bugfixes in there as well.

well you will be happy to know the UPNP library is fixed.

That being said how the UPNP_Device discover function works is it send the broadcats only to get the IP address of a device. then it performs a direct query. this is something that you cannot do with the Device Sniffer. so the TV may not broadcast the UPNP classes but if directly queried it might.
there is still access to volume and mute. and it appears as tho there is a mechanism to possibly locate apps to be able to launch them.

@kdschlosser Thanks for all the work on this.  This generally works for me, but I only get a results with IP=<IP_ADDRESS>;  <IP_ADDRESS> and my tvs IP don't return anything.  Also  the " creating UPNPObject instance" portion errors on a specific device on my network (directv) - see below.  Any idea on this? or maybe just put that code in a try-catch block and ignore this exception, since we don't care that device anyway?
SSDP: <IP_ADDRESS>
b'M-SEARCH * HTTP/1.1\r\nHOST: <IP_ADDRESS>:1900\r\nMAN: "ssdp:discover"\r\nMX: 1\r\nST: upnp:rootdevice\r\nCONTENT-LENGTH: 0\r\n\r\n'
SSDP: <IP_ADDRESS> - > b'HTTP/1.1 200 OK\r\nCache-Control: max-age=1800\r\nEXT: \r\nLocation: http://<IP_ADDRESS>:49152/0/description.xml\r\nServer: Linux/3.3.8-3.0, UPnP/1.0 DIRECTV JHUPnP/1.0\r\nST: upnp:rootdevice\r\nUSN: uuid:d0545652-5655-5352-5652-023845852682::upnp:rootdevice\r\n\r\n'
SSDP: <IP_ADDRESS> found st: b'upnp:rootdevice'
SSDP: <IP_ADDRESS> found location: b'http://<IP_ADDRESS>:49152/0/description.xml'
SSDP: <IP_ADDRESS> - > b'HTTP/1.1 200 OK\r\nCache-Control: max-age=1800\r\nEXT: \r\nLocation: http://<IP_ADDRESS>:49152/2/description.xml\r\nServer: Linux/3.3.8-3.0, UPnP/1.0 DIRECTV JHUPnP/1.0\r\nST: upnp:rootdevice\r\nUSN: uuid:DIRECTV2PC-Media-Server1_0-RID-023845852682::upnp:rootdevice\r\n\r\n'
SSDP: <IP_ADDRESS> - > b'HTTP/1.1 200 OK\r\nCache-Control: max-age=1800\r\nEXT: \r\nLocation: http://<IP_ADDRESS>:49152/4/description.xml\r\nServer: Linux/3.3.8-3.0, UPnP/1.0 DIRECTV JHUPnP/1.0\r\nST: upnp:rootdevice\r\nUSN: uuid:29bbe0e1-1a6e-47f6-8f8d-6cb56b4ce9f1::upnp:rootdevice\r\n\r\n'
SSDP: <IP_ADDRESS> - > b'HTTP/1.1 200 OK\r\nCache-Control: max-age=1800\r\nEXT: \r\nLocation: http://<IP_ADDRESS>:49152/0/description.xml\r\nServer: Linux/3.3.8-3.0, UPnP/1.0 DIRECTV JHUPnP/1.0\r\nST: upnp:rootdevice\r\nUSN: uuid:d0545652-5655-5352-5652-023845852682::upnp:rootdevice\r\n\r\n'
SSDP: <IP_ADDRESS> - > b'HTTP/1.1 200 OK\r\nCache-Control: max-age=1800\r\nEXT: \r\nLocation: http://<IP_ADDRESS>:49152/2/description.xml\r\nServer: Linux/3.3.8-3.0, UPnP/1.0 DIRECTV JHUPnP/1.0\r\nST: upnp:rootdevice\r\nUSN: uuid:DIRECTV2PC-Media-Server1_0-RID-023845852682::upnp:rootdevice\r\n\r\n'
SSDP: <IP_ADDRESS> - > b'HTTP/1.1 200 OK\r\nCache-Control: max-age=1800\r\nEXT: \r\nLocation: http://<IP_ADDRESS>:49152/4/description.xml\r\nServer: Linux/3.3.8-3.0, UPnP/1.0 DIRECTV JHUPnP/1.0\r\nST: upnp:rootdevice\r\nUSN: uuid:29bbe0e1-1a6e-47f6-8f8d-6cb56b4ce9f1::upnp:rootdevice\r\n\r\n'
SSDP: <IP_ADDRESS> - > b'HTTP/1.1 200 OK\r\nCache-Control: max-age=1800\r\nEXT: \r\nLocation: http://<IP_ADDRESS>:49152/0/description.xml\r\nServer: Linux/3.3.8-3.0, UPnP/1.0 DIRECTV JHUPnP/1.0\r\nST: upnp:rootdevice\r\nUSN: uuid:d0545652-5655-5352-5652-023845852682::upnp:rootdevice\r\n\r\n'
SSDP: <IP_ADDRESS> - > b'HTTP/1.1 200 OK\r\nCache-Control: max-age=1800\r\nEXT: \r\nLocation: http://<IP_ADDRESS>:49152/2/description.xml\r\nServer: Linux/3.3.8-3.0, UPnP/1.0 DIRECTV JHUPnP/1.0\r\nST: upnp:rootdevice\r\nUSN: uuid:DIRECTV2PC-Media-Server1_0-RID-023845852682::upnp:rootdevice\r\n\r\n'
SSDP: <IP_ADDRESS> - > b'HTTP/1.1 200 OK\r\nCache-Control: max-age=1800\r\nEXT: \r\nLocation: http://<IP_ADDRESS>:49152/4/description.xml\r\nServer: Linux/3.3.8-3.0, UPnP/1.0 DIRECTV JHUPnP/1.0\r\nST: upnp:rootdevice\r\nUSN: uuid:29bbe0e1-1a6e-47f6-8f8d-6cb56b4ce9f1::upnp:rootdevice\r\n\r\n'
SSDP: <IP_ADDRESS> - > b'HTTP/1.1 200 OK\r\nCache-Control: max-age=1800\r\nEXT: \r\nLocation: http://<IP_ADDRESS>:49152/0/description.xml\r\nServer: Linux/3.3.8-3.0, UPnP/1.0 DIRECTV JHUPnP/1.0\r\nST: upnp:rootdevice\r\nUSN: uuid:d0545652-5655-5352-5652-023845852682::upnp:rootdevice\r\n\r\n'
SSDP: <IP_ADDRESS> - > b'HTTP/1.1 200 OK\r\nCache-Control: max-age=1800\r\nEXT: \r\nLocation: http://<IP_ADDRESS>:49152/2/description.xml\r\nServer: Linux/3.3.8-3.0, UPnP/1.0 DIRECTV JHUPnP/1.0\r\nST: upnp:rootdevice\r\nUSN: uuid:DIRECTV2PC-Media-Server1_0-RID-023845852682::upnp:rootdevice\r\n\r\n'
SSDP: <IP_ADDRESS> - > b'HTTP/1.1 200 OK\r\nCache-Control: max-age=1800\r\nEXT: \r\nLocation: http://<IP_ADDRESS>:49152/4/description.xml\r\nServer: Linux/3.3.8-3.0, UPnP/1.0 DIRECTV JHUPnP/1.0\r\nST: upnp:rootdevice\r\nUSN: uuid:29bbe0e1-1a6e-47f6-8f8d-6cb56b4ce9f1::upnp:rootdevice\r\n\r\n'
SSDP: <IP_ADDRESS> - > b'HTTP/1.1 200 OK\r\nCache-Control: max-age=1800\r\nEXT: \r\nLocation: http://<IP_ADDRESS>:49152/0/description.xml\r\nServer: Linux/3.3.8-3.0, UPnP/1.0 DIRECTV JHUPnP/1.0\r\nST: upnp:rootdevice\r\nUSN: uuid:d0545652-5655-5352-5652-023845852682::upnp:rootdevice\r\n\r\n'
SSDP: <IP_ADDRESS> - > b'HTTP/1.1 200 OK\r\nCache-Control: max-age=1800\r\nEXT: \r\nLocation: http://<IP_ADDRESS>:49152/2/description.xml\r\nServer: Linux/3.3.8-3.0, UPnP/1.0 DIRECTV JHUPnP/1.0\r\nST: upnp:rootdevice\r\nUSN: uuid:DIRECTV2PC-Media-Server1_0-RID-023845852682::upnp:rootdevice\r\n\r\n'
SSDP: <IP_ADDRESS> - > b'HTTP/1.1 200 OK\r\nCache-Control: max-age=1800\r\nEXT: \r\nLocation: http://<IP_ADDRESS>:49152/4/description.xml\r\nServer: Linux/3.3.8-3.0, UPnP/1.0 DIRECTV JHUPnP/1.0\r\nST: upnp:rootdevice\r\nUSN: uuid:29bbe0e1-1a6e-47f6-8f8d-6cb56b4ce9f1::upnp:rootdevice\r\n\r\n'
SSDP: <IP_ADDRESS> - > b'HTTP/1.1 200 OK\r\nCache-Control: max-age=1800\r\nEXT: \r\nLocation: http://<IP_ADDRESS>:49152/0/description.xml\r\nServer: Linux/3.3.8-3.0, UPnP/1.0 DIRECTV JHUPnP/1.0\r\nST: upnp:rootdevice\r\nUSN: uuid:d0545652-5655-5352-5652-023845852682::upnp:rootdevice\r\n\r\n'
SSDP: <IP_ADDRESS> - > b'HTTP/1.1 200 OK\r\nCache-Control: max-age=1800\r\nEXT: \r\nLocation: http://<IP_ADDRESS>:49152/2/description.xml\r\nServer: Linux/3.3.8-3.0, UPnP/1.0 DIRECTV JHUPnP/1.0\r\nST: upnp:rootdevice\r\nUSN: uuid:DIRECTV2PC-Media-Server1_0-RID-023845852682::upnp:rootdevice\r\n\r\n'
SSDP: <IP_ADDRESS> - > b'HTTP/1.1 200 OK\r\nCache-Control: max-age=1800\r\nEXT: \r\nLocation: http://<IP_ADDRESS>:49152/4/description.xml\r\nServer: Linux/3.3.8-3.0, UPnP/1.0 DIRECTV JHUPnP/1.0\r\nST: upnp:rootdevice\r\nUSN: uuid:29bbe0e1-1a6e-47f6-8f8d-6cb56b4ce9f1::upnp:rootdevice\r\n\r\n'
SSDP: <IP_ADDRESS> - > b'HTTP/1.1 200 OK\r\nCache-Control: max-age=1800\r\nEXT: \r\nLocation: http://<IP_ADDRESS>:49152/0/description.xml\r\nServer: Linux/3.3.8-3.0, UPnP/1.0 DIRECTV JHUPnP/1.0\r\nST: upnp:rootdevice\r\nUSN: uuid:d0545652-5655-5352-5652-023845852682::upnp:rootdevice\r\n\r\n'
SSDP: <IP_ADDRESS> - > b'HTTP/1.1 200 OK\r\nCache-Control: max-age=1800\r\nEXT: \r\nLocation: http://<IP_ADDRESS>:49152/2/description.xml\r\nServer: Linux/3.3.8-3.0, UPnP/1.0 DIRECTV JHUPnP/1.0\r\nST: upnp:rootdevice\r\nUSN: uuid:DIRECTV2PC-Media-Server1_0-RID-023845852682::upnp:rootdevice\r\n\r\n'
SSDP: <IP_ADDRESS> - > b'HTTP/1.1 200 OK\r\nCache-Control: max-age=1800\r\nEXT: \r\nLocation: http://<IP_ADDRESS>:49152/4/description.xml\r\nServer: Linux/3.3.8-3.0, UPnP/1.0 DIRECTV JHUPnP/1.0\r\nST: upnp:rootdevice\r\nUSN: uuid:29bbe0e1-1a6e-47f6-8f8d-6cb56b4ce9f1::upnp:rootdevice\r\n\r\n'
SSDP: <IP_ADDRESS> - > b'HTTP/1.1 200 OK\r\nCache-Control: max-age=1800\r\nEXT: \r\nLocation: http://<IP_ADDRESS>:49152/0/description.xml\r\nServer: Linux/3.3.8-3.0, UPnP/1.0 DIRECTV JHUPnP/1.0\r\nST: upnp:rootdevice\r\nUSN: uuid:d0545652-5655-5352-5652-023845852682::upnp:rootdevice\r\n\r\n'
SSDP: <IP_ADDRESS> - > b'HTTP/1.1 200 OK\r\nCache-Control: max-age=1800\r\nEXT: \r\nLocation: http://<IP_ADDRESS>:49152/2/description.xml\r\nServer: Linux/3.3.8-3.0, UPnP/1.0 DIRECTV JHUPnP/1.0\r\nST: upnp:rootdevice\r\nUSN: uuid:DIRECTV2PC-Media-Server1_0-RID-023845852682::upnp:rootdevice\r\n\r\n'
SSDP: <IP_ADDRESS> - > b'HTTP/1.1 200 OK\r\nCache-Control: max-age=1800\r\nEXT: \r\nLocation: http://<IP_ADDRESS>:49152/4/description.xml\r\nServer: Linux/3.3.8-3.0, UPnP/1.0 DIRECTV JHUPnP/1.0\r\nST: upnp:rootdevice\r\nUSN: uuid:29bbe0e1-1a6e-47f6-8f8d-6cb56b4ce9f1::upnp:rootdevice\r\n\r\n'
SSDP: <IP_ADDRESS> - > b'HTTP/1.1 200 OK\r\nCache-Control: max-age=1800\r\nEXT: \r\nLocation: http://<IP_ADDRESS>:49152/0/description.xml\r\nServer: Linux/3.3.8-3.0, UPnP/1.0 DIRECTV JHUPnP/1.0\r\nST: upnp:rootdevice\r\nUSN: uuid:d0545652-5655-5352-5652-023845852682::upnp:rootdevice\r\n\r\n'
SSDP: <IP_ADDRESS> - > b'HTTP/1.1 200 OK\r\nCache-Control: max-age=1800\r\nEXT: \r\nLocation: http://<IP_ADDRESS>:49152/2/description.xml\r\nServer: Linux/3.3.8-3.0, UPnP/1.0 DIRECTV JHUPnP/1.0\r\nST: upnp:rootdevice\r\nUSN: uuid:DIRECTV2PC-Media-Server1_0-RID-023845852682::upnp:rootdevice\r\n\r\n'
SSDP: <IP_ADDRESS> - > b'HTTP/1.1 200 OK\r\nCache-Control: max-age=1800\r\nEXT: \r\nLocation: http://<IP_ADDRESS>:49152/4/description.xml\r\nServer: Linux/3.3.8-3.0, UPnP/1.0 DIRECTV JHUPnP/1.0\r\nST: upnp:rootdevice\r\nUSN: uuid:29bbe0e1-1a6e-47f6-8f8d-6cb56b4ce9f1::upnp:rootdevice\r\n\r\n'
SSDP: <IP_ADDRESS> - > b'HTTP/1.1 200 OK\r\nCache-Control: max-age=1800\r\nEXT: \r\nLocation: http://<IP_ADDRESS>:49152/0/description.xml\r\nServer: Linux/3.3.8-3.0, UPnP/1.0 DIRECTV JHUPnP/1.0\r\nST: upnp:rootdevice\r\nUSN: uuid:d0545652-5655-5352-5652-023845852682::upnp:rootdevice\r\n\r\n'
SSDP: <IP_ADDRESS> - > b'HTTP/1.1 200 OK\r\nCache-Control: max-age=1800\r\nEXT: \r\nLocation: http://<IP_ADDRESS>:49152/2/description.xml\r\nServer: Linux/3.3.8-3.0, UPnP/1.0 DIRECTV JHUPnP/1.0\r\nST: upnp:rootdevice\r\nUSN: uuid:DIRECTV2PC-Media-Server1_0-RID-023845852682::upnp:rootdevice\r\n\r\n'
SSDP: <IP_ADDRESS> - > b'HTTP/1.1 200 OK\r\nCache-Control: max-age=1800\r\nEXT: \r\nLocation: http://<IP_ADDRESS>:49152/4/description.xml\r\nServer: Linux/3.3.8-3.0, UPnP/1.0 DIRECTV JHUPnP/1.0\r\nST: upnp:rootdevice\r\nUSN: uuid:29bbe0e1-1a6e-47f6-8f8d-6cb56b4ce9f1::upnp:rootdevice\r\n\r\n'
SSDP: <IP_ADDRESS> - > b'HTTP/1.1 200 OK\r\nDate: Sun, Dec  9 01:02:31 2018\r\nCache-Control: max-age=1800\r\nExt: \r\nServer: Linux/2.6.22 UPnP/1.1 JetHeadInc/1\r\nLOCATION: http://<IP_ADDRESS>:63444/upnp/xml/devices/ManageableDevice1.xml\r\nST: upnp:rootdevice\r\nUSN: uuid:ManageableDevice-08_EB_74_86_88_0D::upnp:rootdevice\r\n\r\n'
SSDP: <IP_ADDRESS> - > b'HTTP/1.1 200 OK\r\nCACHE-CONTROL: max-age=120\r\nST: upnp:rootdevice\r\nUSN: uuid:14194637-60e7-4ef9-b3f3-ef9c49947396::upnp:rootdevice\r\nEXT:\r\nSERVER: Debian/wheezy UPnP/1.1 MiniUPnPd/2.0\r\nLOCATION: http://<IP_ADDRESS>:53583/rootDesc.xml\r\nOPT: "http://schemas.upnp.org/upnp/1/0/"; ns=01\r\n01-NLS:<PHONE_NUMBER>\r\nBOOTID.UPNP.ORG:<PHONE_NUMBER>\r\nCONFIGID.UPNP.ORG: 1337\r\n\r\n'
SSDP: <IP_ADDRESS> - > b'HTTP/1.1 200 OK\r\nCACHE-CONTROL: max-age=120\r\nST: upnp:rootdevice\r\nUSN: uuid:14194637-60e7-4ef9-b3f3-ef9c49947396::upnp:rootdevice\r\nEXT:\r\nSERVER: Debian/wheezy UPnP/1.1 MiniUPnPd/2.0\r\nLOCATION: http://<IP_ADDRESS>:53583/rootDesc.xml\r\nOPT: "http://schemas.upnp.org/upnp/1/0/"; ns=01\r\n01-NLS:<PHONE_NUMBER>\r\nBOOTID.UPNP.ORG:<PHONE_NUMBER>\r\nCONFIGID.UPNP.ORG: 1337\r\n\r\n'
SSDP: <IP_ADDRESS> - > b'HTTP/1.1 200 OK\r\nCACHE-CONTROL: max-age=120\r\nST: upnp:rootdevice\r\nUSN: uuid:14194637-60e7-4ef9-b3f3-ef9c49947396::upnp:rootdevice\r\nEXT:\r\nSERVER: Debian/wheezy UPnP/1.1 MiniUPnPd/2.0\r\nLOCATION: http://<IP_ADDRESS>:53583/rootDesc.xml\r\nOPT: "http://schemas.upnp.org/upnp/1/0/"; ns=01\r\n01-NLS:<PHONE_NUMBER>\r\nBOOTID.UPNP.ORG:<PHONE_NUMBER>\r\nCONFIGID.UPNP.ORG: 1337\r\n\r\n'
SSDP: <IP_ADDRESS> - > b'HTTP/1.1 200 OK\r\nCACHE-CONTROL: max-age=120\r\nST: upnp:rootdevice\r\nUSN: uuid:14194637-60e7-4ef9-b3f3-ef9c49947396::upnp:rootdevice\r\nEXT:\r\nSERVER: Debian/wheezy UPnP/1.1 MiniUPnPd/2.0\r\nLOCATION: http://<IP_ADDRESS>:53583/rootDesc.xml\r\nOPT: "http://schemas.upnp.org/upnp/1/0/"; ns=01\r\n01-NLS:<PHONE_NUMBER>\r\nBOOTID.UPNP.ORG:<PHONE_NUMBER>\r\nCONFIGID.UPNP.ORG: 1337\r\n\r\n'
SSDP: <IP_ADDRESS> - > b'HTTP/1.1 200 OK\r\nCACHE-CONTROL: max-age=120\r\nST: upnp:rootdevice\r\nUSN: uuid:14194637-60e7-4ef9-b3f3-ef9c49947396::upnp:rootdevice\r\nEXT:\r\nSERVER: Debian/wheezy UPnP/1.1 MiniUPnPd/2.0\r\nLOCATION: http://<IP_ADDRESS>:53583/rootDesc.xml\r\nOPT: "http://schemas.upnp.org/upnp/1/0/"; ns=01\r\n01-NLS:<PHONE_NUMBER>\r\nBOOTID.UPNP.ORG:<PHONE_NUMBER>\r\nCONFIGID.UPNP.ORG: 1337\r\n\r\n'
SSDP: <IP_ADDRESS> - > b'HTTP/1.1 200 OK\r\nDate: Sun, Dec  9 01:03:19 2018\r\nCache-Control: max-age=1800\r\nExt: \r\nServer: Linux/2.6.22 UPnP/1.1 JetHeadInc/1\r\nLOCATION: http://<IP_ADDRESS>:63444/upnp/xml/devices/ManageableDevice1.xml\r\nST: upnp:rootdevice\r\nUSN: uuid:ManageableDevice-08_EB_74_19_61_13::upnp:rootdevice\r\n\r\n'
SSDP: <IP_ADDRESS> - > b'HTTP/1.1 200 OK\r\nDate: Sun, Dec  9 01:02:31 2018\r\nCache-Control: max-age=1800\r\nExt: \r\nServer: Linux/2.6.22 UPnP/1.1 JetHeadInc/1\r\nLOCATION: http://<IP_ADDRESS>:63444/upnp/xml/devices/ManageableDevice1.xml\r\nST: upnp:rootdevice\r\nUSN: uuid:ManageableDevice-08_EB_74_86_88_0D::upnp:rootdevice\r\n\r\n'
SSDP: <IP_ADDRESS> - > b'HTTP/1.1 200 OK\r\nDate: Sun, Dec  9 01:03:19 2018\r\nCache-Control: max-age=1800\r\nExt: \r\nServer: Linux/2.6.22 UPnP/1.1 JetHeadInc/1\r\nLOCATION: http://<IP_ADDRESS>:63444/upnp/xml/devices/ManageableDevice1.xml\r\nST: upnp:rootdevice\r\nUSN: uuid:ManageableDevice-08_EB_74_19_61_13::upnp:rootdevice\r\n\r\n'
SSDP: <IP_ADDRESS> - > b'HTTP/1.1 200 OK\r\nDate: Sun, Dec  9 01:02:31 2018\r\nCache-Control: max-age=1800\r\nExt: \r\nServer: Linux/2.6.22 UPnP/1.1 JetHeadInc/1\r\nLOCATION: http://<IP_ADDRESS>:63444/upnp/xml/devices/ManageableDevice1.xml\r\nST: upnp:rootdevice\r\nUSN: uuid:ManageableDevice-08_EB_74_86_88_0D::upnp:rootdevice\r\n\r\n'
SSDP: <IP_ADDRESS> - > b'HTTP/1.1 200 OK\r\nDate: Sun, Dec  9 01:02:31 2018\r\nCache-Control: max-age=1800\r\nExt: \r\nServer: Linux/2.6.22 UPnP/1.1 JetHeadInc/1\r\nLOCATION: http://<IP_ADDRESS>:63444/upnp/xml/devices/ManageableDevice1.xml\r\nST: upnp:rootdevice\r\nUSN: uuid:ManageableDevice-08_EB_74_86_88_0D::upnp:rootdevice\r\n\r\n'
SSDP: <IP_ADDRESS> - > b'HTTP/1.1 200 OK\r\nDate: Sun, Dec  9 01:03:19 2018\r\nCache-Control: max-age=1800\r\nExt: \r\nServer: Linux/2.6.22 UPnP/1.1 JetHeadInc/1\r\nLOCATION: http://<IP_ADDRESS>:63444/upnp/xml/devices/ManageableDevice1.xml\r\nST: upnp:rootdevice\r\nUSN: uuid:ManageableDevice-08_EB_74_19_61_13::upnp:rootdevice\r\n\r\n'
SSDP: <IP_ADDRESS> - > b'HTTP/1.1 200 OK\r\nDate: Sun, Dec  9 01:03:19 2018\r\nCache-Control: max-age=1800\r\nExt: \r\nServer: Linux/2.6.22 UPnP/1.1 JetHeadInc/1\r\nLOCATION: http://<IP_ADDRESS>:63444/upnp/xml/devices/ManageableDevice1.xml\r\nST: upnp:rootdevice\r\nUSN: uuid:ManageableDevice-08_EB_74_19_61_13::upnp:rootdevice\r\n\r\n'
SSDP: <IP_ADDRESS> - > b'HTTP/1.1 200 OK\r\nDate: Sun, Dec  9 01:03:19 2018\r\nCache-Control: max-age=1800\r\nExt: \r\nServer: Linux/2.6.22 UPnP/1.1 JetHeadInc/1\r\nLOCATION: http://<IP_ADDRESS>:63444/upnp/xml/devices/ManageableDevice1.xml\r\nST: upnp:rootdevice\r\nUSN: uuid:ManageableDevice-08_EB_74_19_61_13::upnp:rootdevice\r\n\r\n'
SSDP: <IP_ADDRESS> - > b'HTTP/1.1 200 OK\r\nDate: Sun, Dec  9 01:02:31 2018\r\nCache-Control: max-age=1800\r\nExt: \r\nServer: Linux/2.6.22 UPnP/1.1 JetHeadInc/1\r\nLOCATION: http://<IP_ADDRESS>:63444/upnp/xml/devices/ManageableDevice1.xml\r\nST: upnp:rootdevice\r\nUSN: uuid:ManageableDevice-08_EB_74_86_88_0D::upnp:rootdevice\r\n\r\n'
SSDP: <IP_ADDRESS> creating UPNPObject instance
Exception in thread Thread-1:
Traceback (most recent call last):
File "C:\Users\bmurr\PycharmProjects\test_upnp_2\venv\lib\site-packages\requests\models.py", line 379, in prepare_url
scheme, auth, host, port, path, query, fragment = parse_url(url)
File "C:\Users\bmurr\PycharmProjects\test_upnp_2\venv\lib\site-packages\urllib3\util\url.py", line 199, in parse_url
raise LocationParseError(url)
urllib3.exceptions.LocationParseError: Failed to parse: <IP_ADDRESS>:49152http:
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "C:\Users\bmurr\AppData\Local\Programs\Python\Python35\lib\threading.py", line 923, in _bootstrap_inner
self.run()
File "C:\Users\bmurr\AppData\Local\Programs\Python\Python35\lib\threading.py", line 871, in run
self._target(*self._args, **self._kwargs)
File "C:\Users\bmurr\AppData\Local\Programs\Python\Python35\lib\UPNP_Device\discover.py", line 426, in found_thread
found_classes.append(UPNPObject(addr, classes))
File "C:\Users\bmurr\AppData\Local\Programs\Python\Python35\lib\UPNP_Device\upnp_class.py", line 24, in call
super(UPNPSingleton, cls).call(ip, classes)
File "C:\Users\bmurr\AppData\Local\Programs\Python\Python35\lib\UPNP_Device\upnp_class.py", line 91, in init
device = UPNPDevice(url, node=device, parent=self)
File "C:\Users\bmurr\AppData\Local\Programs\Python\Python35\lib\UPNP_Device\upnp_class.py", line 189, in init
service = Service(self, url, scpdurl, service_type, control_url)
File "C:\Users\bmurr\AppData\Local\Programs\Python\Python35\lib\UPNP_Device\service.py", line 38, in init
response = requests.get(url + location)
File "C:\Users\bmurr\PycharmProjects\test_upnp_2\venv\lib\site-packages\requests\api.py", line 75, in get
return request('get', url, params=params, **kwargs)
File "C:\Users\bmurr\PycharmProjects\test_upnp_2\venv\lib\site-packages\requests\api.py", line 60, in request
return session.request(method=method, url=url, **kwargs)
File "C:\Users\bmurr\PycharmProjects\test_upnp_2\venv\lib\site-packages\requests\sessions.py", line 519, in request
prep = self.prepare_request(req)
File "C:\Users\bmurr\PycharmProjects\test_upnp_2\venv\lib\site-packages\requests\sessions.py", line 462, in prepare_request
hooks=merge_hooks(request.hooks, self.hooks),
File "C:\Users\bmurr\PycharmProjects\test_upnp_2\venv\lib\site-packages\requests\models.py", line 313, in prepare
self.prepare_url(url, params)
File "C:\Users\bmurr\PycharmProjects\test_upnp_2\venv\lib\site-packages\requests\models.py", line 381, in prepare_url
raise InvalidURL(*e.args)
requests.exceptions.InvalidURL: Failed to parse: <IP_ADDRESS>:49152http:

the UPNP_Device library is a separate library I made. it is not specific to only Samsung product. It's so others can use it if they wanted to control say a network attached TV tuner. It also means that if there is an error in it now. that there could be later in the future if Samsung changes something that doesn't agree. so we have to make sure this portion is all nice and cleaned up. to keep from having problems in the future.
Now. that being stated. the line that the error is pointing to that pertaint to the UPNP_Device library
File "C:\Users\bmurr\AppData\Local\Programs\Python\Python35\lib\UPNP_Device\service.py", line 38, in init
response = requests.get(url + location)

line 38. there is nothing on that line in the latest version of the program. the highlighted line in the image below is the line that is mentioned in the error. which according to that error should read
response = requests.get(url + location)

but doesn't

You need to download the latest version from the lxml branch.
you can get to the lxml branch with this link
https://github.com/kdschlosser/UPNP_Device/tree/lxml
then click on the clone or download button and save it as a zip. decompress it to some temp folder. start a console (linux) or a command prompt (windows) navigate to that temp folder. and run the setup.py as outlined below.
python setup.py install

you have to run the setup.py. this will install any requirements that are necessary. in this case it would be lxml.

ok so here goes another try.
I do want to mention that if you have installed it this way before go into your siite packages folder and delete the one that is in there. it is going to be a file with the extension of .egg. then edit
easy-install.pth

it is in the same location as the .egg file.
find the line pointing to that .egg file and delete it.
download the version from this link. https://github.com/kdschlosser/samsungctl/tree/updated_upnp_features
to install it run the following command
python setup.py install

and here is a basic script to see if it works.
from samsungctl import Remote

remote = Remote(log_level=Remote.LOG_DEBUG)
print(remote.upnp_tv)

or you can use this script if you want to specify the IP of the TV change the MY_TV_IP variable to the address of your TV
MY_TV_IP = '<IP_ADDRESS>'
from samsungctl import Remote

remote = Remote(ip_address=MY_TV_IP, log_level=Remote.LOG_DEBUG)
print(remote.upnp_tv)

I forgot to mention. if you so choose the old way
from samsungctl import Remote

config = {
"name": "samsungctl",
"description": "PC",
"id": "",
"method": "legacy",
"port": 55000,
"timeout": 0
}

remote = Remote(config , log_level=Remote.LOG_DEBUG)
while remote.is_discovering:
    pass

print(remote.upnp_tv)

i set this up so that if you pass a config file it will use that config file to make the remote connection first. and then it launches a thread to do the discovery side of things. So the library will actually still function if the UPNP end of things is not functioning for some reason. so I added a mechanism to be able to tell if the TV is still discovering the TV.
if you do not pass a config file and simply pass an IP or let it automatically discover there are bits of information that needs to be obtained from the UPNP side of things in order to get the remote portion working. so there is no thread that gets launched. it keeps in all within the thread that created the Remote instance.

Nice!  I should be able to use this with openhab i think?

if openhab supports python then yes.

@kdschlosser Awesome work!  One of the problems we have in Homesassistant is just knowing if the TV is on or off.  All the solutions have been kinda flakey given all the different tv models. Any chance this library can subscribe to events?  I noticed the TV sends an SSDP:byebye when you turn it off and SSDP:alive periodically.  I'd think we could leverage that to understand the actual TV power state?
Thanks!

having the TV show a power state is easy to do. and from what i have seen the TV's do not have any events that can be subscribed to. but we can do up some simple polling to get the job done. it would monitor whether or not the TV is on (responding to SSDP packets) and checking the status of the various elements like volume and mute. and see if they match values that we store for the device. and if they do not match an event can be generated.
it appears as tho Samsung has removed all of the TV tuner controls from the newer TV's as well as the ability to control what the input is which really sucks. nothing I can do about that. they have probably migrated everything to the websocket connection. but there really is no way to know. I am going to send an email off to Samsung to request the source code for the smartview application. the app is open source. so maybe that may give some insight.

I would rather not bind to a socket to wait for an SSDP byebye from the TV. the reason being is that if something happens with the program whether it be samsungctl or the program that is running it, and the socket does not get closed properly we will end up with an orphaned socket. so i would like to steer clear of doing that.

Maybe some inspiration can be had from this project
https://github.com/tavicu/homebridge-samsung-tizen

well well. that did give me the mechanism to be able to get the app ID's
It will take a while to acquire them but they can be had.

if someone is willing to run this script and set the TV_IP to the IP address of your TV. and paste the data to me that would be helpful. you will need to have the YouTube app installed for this to work.
import requests
TV_IP = '<IP_ADDRESS>'

response = requests.get('http://' + TV_IP + ':8001/api/v2/applications/111299001912')
print(response.content)

{"id":"111299001912","name":"YouTube","running":true,"version":"2.1.486","visible":false}
Is what I got from running the link in my browser

ok cool

@kdschlosser
Did you happen to see this thread?  i think this thread tracked down some of the app ids already:
https://github.com/Ape/samsungctl/issues/75

yeah only some. I am going to go after as man as i can get a hold of
here is a script that is going to have to run for a long time. probably several days. You will be able to check and see if it got all the applications on your TV by looking in the folder and counting the number of files and then counting the number of applications on the TV
you will need to change the TV_IP to be your TV ip address.
This is set up to be run on Windows it will make a directory called samsung_application_ids on your desktop, in that directory it will put a file for every application it finds. this is a brute force number deal. I started with the application ID for NetFlix as it is the lowest number therefor has been around the longest time. there are 10 threads that run querying the TV if there is no application at that number then it will get an error and the thread moves to the next number.
it will spit out app numbers it is trying to the console. so you know it's working.
import requests
import threading
import os
import json

TV_IP = '<IP_ADDRESS>'

# {
#     "id": "111299001912",
#     "name": "YouTube",
#     "running": True,
#     "version": "2.1.486",
#     "visible": False
# }

OUTPUT_PATH = os.path.expandvars(
    os.path.join('%userprofile%', 'desktop', 'samsung_application_ids')
)

file_save_count = 0

if not os.path.exists(OUTPUT_PATH):
    os.mkdir(OUTPUT_PATH)

count =<PHONE_NUMBER>0

url = 'http://{0}:8001/api/v2/applications/'.format(TV_IP)

def do():
    global count
    global file_save_count
    while True:
        t_count = count
        count += 1000
        end_count = t_count + 999
        while t_count != end_count:
            print(t_count)
            try:
                response = requests.get(url + str(t_count), timeout=5)
                content = json.loads(response.content)
                try:
                    with open(os.path.join(OUTPUT_PATH, content['name'] + '.txt'), 'w') as f:
                        f.write(json.dumps(content, indent=4))
                except KeyError:
                    pass
                except:
                    save_count = file_save_count
                    file_save_count += 1
                    with open(os.path.join(OUTPUT_PATH, str(save_count) + '.txt'), 'w') as f:
                        f.write(json.dumps(content, indent=4))
            except:
                pass

for _ in range(10):
    t = threading.Thread(target=do)
    t.daemon = True
    t.start()

event = threading.Event()

event.wait()

The code above will not work. Apparently not all of the apps will show up there. It doesn't matter anyway. I managed to get my hands on large portions of the Samsung TV OS source code. And k do believe the websocket bits are in it. This is going to make engineering an API a whole lot easier.

Hi
for some reason i get the following error while trying any scripts:
raceback (most recent call last):   File "test.py", line 3, in <module>     remote = Remote(log_level=Remote.LOG_DEBUG)   File "/usr/local/lib/python2.7/dist-packages/samsungctl-0.7.1+1-py2.7.egg/samsungctl/remote.py", line 22, in __init__     self._discovering = threading.Event()   File "/usr/local/lib/python2.7/dist-packages/samsungctl-0.7.1+1-py2.7.egg/samsungctl/remote.py", line 100, in __setattr__     if self.upnp_tv is not None:   File "/usr/local/lib/python2.7/dist-packages/samsungctl-0.7.1+1-py2.7.egg/samsungctl/remote.py", line 93, in __getattr__     if self.upnp_tv is not None:   File "/usr/local/lib/python2.7/dist-packages/samsungctl-0.7.1+1-py2.7.egg/samsungctl/remote.py", line 93, in __getattr__     if self.upnp_tv is not None: <.... Snipped out about 100 times repetition of line 93 errors ...>   File "/usr/local/lib/python2.7/dist-packages/samsungctl-0.7.1+1-py2.7.egg/samsungctl/remote.py", line 93, in __getattr__     if self.upnp_tv is not None: RuntimeError: maximum recursion depth exceeded
Any Idea ? This is on ubuntu lts Python 2.7.15rc1

@kdschlosser
Btw why do you need IDs of all possible applications?
We are retrieving all apps installed on particular TV by WebSocket with the following commands:
// get installed apps
send({
     method: 'ms.channel.emit',
     params: {
         event: 'ed.installedApp.get',
         to: 'host',
         data: { },
     }
});

// get eden apps (with more extra info)
send({
     method: 'ms.channel.emit',
     params: {
         event: 'ed.edenApp.get',
         to: 'host',
         data: { },
     }
});

Hi @kdschlosser ... can you give me hint regarding my issue above ... (i don't have a very good python knowledge) ... that would be awesome.
Thanks

that is a test version that had some issues. i am still tinkering about with it to get things corrected.
so here is an example of things working properly with my older generation TV, wish I had a newer one to develop with it would make things far easier.
so here is the example I have.
Here you can see the ability to select a source. this is a list that is retrieved form the TV

and in this screen shot you can see the list on the right that contains only a partial list of what can be done on the TV. and on the left the lines with the Leggo looking icons represent me sending a command to the TV. and the lines with the lightning bolt are "events" or notifications that things have changed on the TV. the events some from data retrieved from the TV. If you look at the response time you will notice that the events are taking place less then a second after I send the command to the TV.

the next few images are to show the rest of the commands

so I am making more progress with this. I think I might have the final things finished up. I have to release a test version of the program that populates this interface into the forums of another project I work on to find out. if successful I will release it here. I have someone that is testing things out for me on that forum.
I did change how the config data is stored. the old API still functions. But I have made it a bit easier for those that do not know JSON.
here are some code examples of how one will be able to use the discovery and old API alike.
from samsungctl import discover, Config, Remote

config = Config.load('path/to/save/file')
tv = discover(config)
config.save()

# or if you want to manually enter the config data

config = Config(
    # not used here for backwards compatibility
    name=None,

    # not used here for backwards compatibility
    description=None,

    # IP of the TV. this gets used if there is no device ID present
    host='<IP_ADDRESS>',

    # this only gets used if the TV cannot be discovered using UPNP or if the
    # old API of passing a dict gets sent directly to Remote which would
    # bypass any UPNP discovery
    # settings are 55000 or 8001
    port=55000,

    # legacy connections and gets automatically generated. But it is here
    # because the old config file used it.
    id=None,

    # not used here for backwards compatibility
    method='legacy',

    # not used here for backwards compatibility
    timeout=0,

    # mainly for internal use. but if you know the token you are more then
    # welcome to enter it. if the token is present the mechanics of discovering
    # if a TV supports ssl or not is bypassed.
    token=None,

    # optional save path for the config file. a path can also be specified
    # when calling config.save
    path=None,

    # if this param is manually entered it has to be the device id gotten from
    # UPNP. this will override the use of the host (IP) when discovering via
    # UPNP. if you use the method above for discovering a TV this is
    # automatically populated
    device_id=None
)

tv = discover(config)
config.save('/path/to/save/file')

# because the library is now going to be able to support multiple TV's through
# the use of the discovery mechanism.

for tv in discover():
    print(tv.name)

# another nice thing is if the user decides to use the TV

for tv in discover():
    answer = raw_input('use TV ' + tv.name + ':')
    if answer.lower() == 'y':
        path = raw_input('config save path:')
        tv.config.save(path)

# if you specify a path that is only a directory the tv model number and the
# device id will get used

# because of the above code if all of the config files are saved to the same
# directory iterating over the directory to pass the file names becomes a snap
# so setting up the configs for the TV's becomes easy.

import os
path = 'path/to/config/files'

tvs = []
for file in  os.listdir(path):
    config = Config.load(os.path.join(path, file))
    tv = discover(config)
    tvs += [tv]

# now to keep things from getting all kinds of out of sorts
# II made a meta class that is an instance singleton. so there can only be a
# single instance of a TV. This will make it it easier to track if a device is
# powered on or off (this method works quite well actually).

tvs = list(discover())
new_tvs = list(discover())

for tv in new_tvs:
    tv.power = True
    if tv not in tvs or not tv.power:
        print('tv powered on ' + tv.name)

for tv in tvs:
    if tv not in new_tvs:
        tv.power = False
        print('tv powered off ' + tv.name)

# and of coarse for supporting a single TV this way still works as well.

config = {
    "name": "samsungctl",
    "description": "PC",
    "id": "",
    "method": "legacy",
    "port": 55000,
    "timeout": 0
}

remote = Remote(config)

# this is a little added bonus a slight twist. You will have to specify the
# filename to save to. the above bypasses the UPNP discovery so the device id
# cannot be obtained.
remote.config.save('/path/to/save/file')

I changed how the config data gets written. I removed the use of storing the config data as a json object in favor of storing it as a flat file. I feel this will make it easier for the programming newbies. and in all honesty there is no reason why the config data should be stored as a json object. there is not enough data to warrant it and none of the data is nested at all. the library of course is backwards compatible with the json files. but when a new one gets written it will be as a flat file. the flat file will look like the following
name = Some TV Name
description = Some TV Description
host = <IP_ADDRESS>
port = 8002
id = Some ID
method = websocket
timeout = 0
token = Token from the websocket
device id = Device ID from UPNP

the arrangement of the lines does not matter. any blank lines does not matter. if you want to add commented lines just make sure they do not have an = in them. all fields are not necessary.

@kdschlosser Ok, Thanks. Do you have an idea of when you plan to commit your most recent changes ?

hopefully soon. I hurt my back yesterday. This is the first time I am sitting down at the computer since then. we will see how much I can get done.

now I know that this appears to give the state of the application
import requests
TV_IP = '<IP_ADDRESS>'

response = requests.get('http://' + TV_IP + ':8001/api/v2/applications/111299001912')
print(response.content)

I do not know if this is the "universal" mechanism across all new TV's
i did find some information in the API about using the mechanism below. who knows with Samsung as to which was will work and which way will not. so better to have both in there. one as a fallback to use.
please post any error or data returned.
change the TV_IP to your TV's IP address.
import requests
TV_IP = '<IP_ADDRESS>'

response = requests.get('http://' + TV_IP + ':8001/api/v2/applications/111299001912/info')
print(response.content)

I stumbled upon @eclair4151 's implementation of the encrypted websocket for the 2014 and 2015 models. I am hoping @eclair4151  doesn't mind. I borrowed the code to add to samsungctl to give full support of all available TV models from 2007+ (I think the IP control started with 2007). I did however have to make a large amount of changes to make it compatible with samsungctl as the original code was only drafted for single use. I also did some reformatting to make it PEP8 compliant as well as made it compatible with python 2.7+

ok so here is a test version again
https://github.com/kdschlosser/samsungctl/tree/yet_another_test_version
I am making changes as I go. so bear with me on these things. Ideas come to me as I am working on it.
typical install script. please run it to get the newest requirements
python setup.py install

here is a simple test script to test with
if you want to capture all of the console output you will need to set the scroll history to a pretty high number. I would say somewhere around 10K would be a good number. if you have more then a single TV then you will need more.
from __future__ import print_function
import samsungctl

for tv in samsungctl.discover():
    print(tv.config)
    print()
    print(tv.upnp_tv)

OK i made a branch that is just a modification of the original library to use the ssl websocket. i removed use of the old style websocket. so this version will only do legacy and websocket ssl. use the original config file that you were using with samsungctl. or pass the exact same config parameters to it as you were before.
This version supports more then a single TV. and it also should overcome the issues with having to run the script as sudo.
https://github.com/kdschlosser/samsungctl/tree/ssl_websocket_only
now remember this works exactly like the original samsungctrl library

please post any error or data returned. change the TV_IP to your TV's IP address.
import requests
TV_IP = '<IP_ADDRESS>'
response = requests.get('http://' + TV_IP + ':8001/api/v2/applications/111299001912/info')
print(response.content)

Tizen 3.0:
curl http://<IP_ADDRESS>:8001/api/v2/applications/111299001912/info
{"code":404,"message":"Not found error.","status":404}

@kdschlosser
When I've researched Samsung api/v2/*, I found this code responsible for http endpoints and websocket api. Currently it seems Samsung moved it out of Tizen open source, but maybe it will help you anyway.
Thank you for all your work!

Yeah I have read all of that already.
But looking at it again made me notice something
htttp://IP:PORT/api/v2/channels/index
htttp://IP:PORT/api/v2/request
htttp://IP:PORT/api/plugin
htttp://IP:PORT/lib/multiscreen-service
htttp://IP:PORT/api/service.json
using your web browser try these urls. changing the IP to your TV IP and try port 8001 and 8002 also.

there is also an api/v3 as well. FYI

http://IP:PORT/api/v2/channels/index
http://IP:PORT/api/v2/request
http://IP:PORT/api/plugin
http://IP:PORT/lib/multiscreen-service
http://IP:PORT/api/service.json
http://IP:PORT/api/v3/

All these urls lead to 404 on my TVs:
Tizen 3.0
<html><body>404</body></html>

Tizen 2.4
{
  "status": 404,
  "message": "Not Found",
  "code": 404
}

well it was a shot to see if anything was there.

I updated the branch located at
https://github.com/kdschlosser/samsungctl/tree/ssl_websocket_only
i change out how the websocket was being created i am now using websocket.WebsocketApp connection instead. This is going to provide some more insight as to what is happening with the connection. so maybe we will get an error besides "the connection is already closed" which tells us nothing about what is happening.
if you run this library from the command line then please be sure to add -vvvv as a CLI switch. this will enable debugging output.
paste the output to me please. working or not I would like to see the output.

I'm not an expert with Python but I did write a UPNP and Websocket implementation from scratch for another home automation platform (HomeSeer) so maybe I can be of some assistance.
Not sure how these PY pieces deal with websockets but you need to send ping and respond to pongs to keep the connection alive.
This thread and some others has been very helpful to me to know how to compose messages and such but also I don't have a latest Samsung TV to test against so I need to rely on other users in the HomeSeer forum to assist in testing. I do make use of the Tizen Emulator but unfortunately the TV emulator is of vintage 2016 so a number of pieces are missing (ex SSL). I'd more than happy to try to pitch in, especially if you have some source code to sift through. I did however look through Tizen sourcecode on-line postings. I can find the REST implementation but the websocket parts are somewhat incomplete, not sure the posting are more recent or older.

Just getting "Error: No such file or directory" when I run this version ... even with -vvvv there's no other output.

@davidgurr thank you for testing. I will make some changes and see if I can get the directory for the token file correct. I do need to know what OS you are running on.
@dcorsus I am in worse shape then you are. I have a really vintage 2011 TV. so I can't even test anything websocket based. The websocket library that we are using is very good. it takes care of keeping the connection alive and all of the other parts and pieces. It simply has multiple ways to handle opening the websocket and each way has some slight variations in how it handles the websocket connections. I know the wai I am using now works. I have had a user tell me that they got the ad remote box to display on the TV. so we are good there. I am now trying to make the thing cross platform. which is what the last error that has been reported above is about

@kdschlosser
You should download the Tizen studio SDK. At least you can test the websocket things (haven't really tried the REST parts). If you use UPNP to discover the devices, the emulator is a bit tricky because it ONLY advertises the MultiScreen service/device as opposed to the IPControl device, which you should see on Samsung TVs 2016 and onward. I did ended up running it on an older PC I had around, a Win7 machine as the emulator gave me issues w the network port bridging.
I do have a 2011 vintage series C where I began implementing remote functions, then I bought a J series in 2015 to find out that this vintage uses yet another encryption mechanism compared to the Tizen line, which now recently forces us into SSL. I do a lot of the websocket and SSL debugging against my LG TV which supports both SSL or non SSL, has a lot of similar principles of discovering apps and starting them like the Samsung BUT it offers a lot more, including eventing over the websocket so you can subscribe to autonomous events that will inform you whether app change, channel change or input source change. They also support ICONs for their apps and unlike the Samsung, it tells you exactly which URL so you can retrieve them. They even event volume settings via the websocket. And the icing on the cake, they still support all else through UPNP (renderer, server ..). Someone yesterday posted me the UPNP info for a Q-Series and pretty much all UPNP functions are disappearing, so no way to get input source selection etc. Feel free to post questions, not sure I can answer them, but I'll share what I know.

@kdschlosser I'm running Raspbian "Stretch" on a Raspberry Pi 3 Model B.
TV is a UE50MU6120

@dcorsus The TV Emulation does not support AMD processors. so I am sol with that.
Samsung has a really goofy UPNP they have shown this on things liike their Air Conditioners. There will always be some form of a UPNP class that can be used to discover the TV. I am trying to leverage the UPNP to get a unique ID for the TV this way there will be no need the TV to a static IP address.
As far as the control ability with samsung the older the TV the better. we do not know what the websocket commands are as of yet. mostly because there isn't even a working type of control on the 2017/2018 models that can be reverse engineered. There is a guy in an issue that is posted under Ape's repo that states they decompiled fixed and then recompiled the smart view app and has it working with newer TV's. I dunno why one would do that because smart view is open source and all that needs to be done is you have to ask samsung for it. I do not know how much control the smart view app offers. On my 2011 it only offers playing media. no control other then that. it would be interesting to see what it does with the newer TV's because if it uses the websocket connection then wireshark can be used to view the packets.
@davidgurr cool I should have that path issue fixed in the next few hours.

@kdschlosser
Hi Kevin, was recently told that SmartThings does NOT show any status info, just remote control buttons and app choices.
What do you mean we do not know what the websocket commands are? I retrieve the app list through websockets and start apps that way, is that what you meant? I actually don't use REST.

There is a whole slew of things that can be controlled through the websocket I am sure.
you can get application lists
start applications
create a mouse pointer and move it.
mouse left and right clicks
input text.
These are just to name the ones that I know of. I am willing to bet there are a whole lot more in terms of commands that are available. we simply have to discover them or when an application to control the newer TV's becomes available from samsung it can be reverse engineered.
smart things is not smart view. 2 different things

Now if i ever decide to do something creative in .net I will make an application for the TV and it's sole purpose would be to relay information to a connected client. for control as well as status updates. The Tizen SDK outlines how to do all of this stuff pretty easily. It also has a method for applications to create theor own websocket ports on the TV. it would simply be a matter of the application registering for events on the TV and then relaying the data out the websocket.

I specifically called out SmartThings because it seems a bit more advanced as opposed to Smartview. I actually compile in a DLL from Smartview to deal with encryption on 2014-2015 model tvs.
I hear you on the embedded app thing, would simplify things a lot. Wonder if we can write apps though that continuously run in the background as opposed to say a netflix or browser app.
What is quite ironic is that the TV does send autonomous IME events via the websocket, not sure what the purpose is or what exactly the encrypted data means. If I start a browser on the TV , I can send text to it or I can see autonomous events when you enter or leave the text entry area.

I think the websocket doesn't just spit out events I have a feeling that we would need to register to have the events given. This is why i state that I believe there is a whole lot more to the websocket API then we know about. but the only way to figure it out is to either get the source code to the OS (or possibly even some older samsung product that has a very similar command structure) or we have to wait until Samsung releases some kind of an application that has expanded functionality and then we can reverse engineer it.

Agree, I would think you need to register somewhere. If you study the source code, they have an interesting principle where clients (apps) can communicate to "host", "all", "client" .... you can even test it by sending something back to yourself ex:
"ms.channel.emit" : {
method : "ms.channel.emit",
params : {
event : "say",
data  : "Hello World!",
to    : "all"
}
124         }
Come to think of it, the ime events actually come from an app (the browser) although that the discovery info hint to ImeSyncedSupport=true but there is also remote_available=true
{"device":{"FrameTVSupport":"false","GamePadSupport":"true","ImeSyncedSupport":"true","OS":"Tizen","TokenAuthSupport":"true","VoiceSupport":"true","countryCode":"NO","description":"Samsung DTV RCR","developerIP":"<IP_ADDRESS>","developerMode":"0","duid":"uuid:c15fc058-0ab1-4c8d-80ca-b3f11d81e291","firmwareVersion":"Unknown","id":"uuid:c15fc058-0ab1-4c8d-80ca-b3f11d81e291","ip":"<IP_ADDRESS>","model":"18_KANTM2_QTV","modelName":"QE65Q9FNA","name":"[TV] Samsung Q9 Series (65)","networkType":"wired","resolution":"3840x2160","smartHubAgreement":"true","type":"Samsung SmartTV","udn":"uuid:c15fc058-0ab1-4c8d-80ca-b3f11d81e291","wifiMac":"c0:48:e6:c3:3b:8d"},"id":"uuid:c15fc058-0ab1-4c8d-80ca-b3f11d81e291","isSupport":"{"DMP_DRM_PLAYREADY":"false","DMP_DRM_WIDEVINE":"false","DMP_available":"true","EDEN_available":"true","FrameTVSupport":"false","ImeSyncedSupport":"true","TokenAuthSupport":"true","remote_available":"true","remote_fourDirections":"true","remote_touchPad":"true","remote_voiceControl":"true"}\n","name":"[TV] Samsung Q9 Series (65)","remote":"1.0","type":"Samsung SmartTV","uri":"http://<IP_ADDRESS>:8001/api/v2/","version":"2.0.25"}

@dcorsus Smarthings with my TV shows the source, or if the source is the in-built tuner, the tuned channel.

@davidgurr cool I should have that path issue fixed in the next few hours.

Have you managed to fix the path issue?

@davidgurr  That is actually good news that SmartThings shows the info we would like to retrieve. Probably asked somewhere, which model Samsung do you have?

@dcorsus it's a UE50MU6120

@dcorsus it's a UE50MU6120

@davidgurr  Thanks for the info. Curious which UPNP services you have. Did you by any chance retrieve that with Kevin's tools? I'm going to check some of my forums, I might have had a person post UPNP info for an M-model.

@dcorsus is that at https://github.com/kdschlosser/UPNP_Device ?

@dcorsus is that at https://github.com/kdschlosser/UPNP_Device ?

@davidgurr You got me there, maybe Kevin can weigh in. I was under the impression there was script or program just to retrieve all the XML files for UPNP from device XML to Service XML. With that info, you can immediately see which features are made available via the UPNP interface and if properly implemented, which services support events. I have a J series and a C series Samsung and neither of them provide many functions through UPNP. I just dug through my info and found a posting of a K-series model, which seems to support many functions through UPNP. The Q series again, don't seem to publish anything through UPNP (URRGGHH).
You don't happen to know how to use wireshark and some network mirroring trick do you :-)

@dcorsus you see how frustrating this is???
@davidgurr yes the UPNP_Device repository
@g10chy I have not yet. I will get to it first thing in the morning (UTC -7:00) (01:33 here now)

@kdschlosser I tried installing the UPNP_Device library, but it fails due to the lack of the lxml library. Tried installing that (pip install lxml) and it locks up my Pi on compiling it. So no joy ...

why come you don't do this from a PC. is there a specific need to do the testing from the Raspberry Pi?

OK this should fix the path issue in linux.
https://github.com/kdschlosser/samsungctl/tree/ssl_websocket_only

that branch was confirmed as working before this latest patch to it I am assuming the user that reported it as working was running Windows. So all i did was put in the proper path for the Linux as to where to save the token file information to
so on Windows it is %appdata%\samsungctl\token.txt
and on every other OS is it ~/.samsungctl/token.txt

I did "samsungctl --host <IP_ADDRESS> KEY_GUIDE" with the following samsungctl.conf:

{
"name": "samsungctl",
"description": "Pi",
"id": "",
"method": "websocket",
"port": 8002,
"timeout": 10
}

Got a prompt from the TV to authorise, then got the following error:

close status: 31522
Traceback (most recent call last):
File "/usr/local/bin/samsungctl", line 11, in
load_entry_point('samsungctl==0.7.1+1', 'console_scripts', 'samsungctl')()
File "build/bdist.linux-armv7l/egg/samsungctl/main.py", line 110, in main
File "build/bdist.linux-armv7l/egg/samsungctl/remote.py", line 11, in init
File "build/bdist.linux-armv7l/egg/samsungctl/remote_websocket.py", line 86, in init
RuntimeError: Auth Failure

@kdschlosser By the way Kevin, I have it now confirmed that with SmartThings and a Q-series, SmartThing does update dynamically (same source told me before it didn't) so it is not through UPNP and it must be through the websocket ... or someother socket (LG actually uses multiple websockets).
So ..... we just need to figure out a way to trace it. I suspect that SmartThings perhaps from day one was using SSL (it doesn't work against J-series) so WireShark tracing might not pan out at all. However, just in the remote case that SmartThings was not using SSL, say against a M-series, that would be our target to go snoop the network.
Still snooping through the posted Tizen source, but so far I only find the things we already know.

Hmm ... that might be it. I'm accepting it but it might not be quick enough. I'll give it another go ...
On Friday, 21 December 2018, 19:28:07 GMT, Kevin Schlosser<EMAIL_ADDRESS>wrote:
ok are you accepting the remote connection on the TV??? it should be prompting you to accept the connection.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub, or mute the thread.

OK, odd results ...
First time, I get the auth prompt, accept (quickly) and the Guide does come up (yay) but I get the following error returned:

Traceback (most recent call last):
File "/usr/local/bin/samsungctl", line 11, in
load_entry_point('samsungctl==0.7.1+1', 'console_scripts', 'samsungctl')()
File "build/bdist.linux-armv7l/egg/samsungctl/main.py", line 112, in main
File "build/bdist.linux-armv7l/egg/samsungctl/remote_websocket.py", line 140, in control
RuntimeError: Receive Failure

Then when I repeat the same command line, I get no auth prompt and no guide displayed, and the following error:

Traceback (most recent call last):
File "/usr/local/bin/samsungctl", line 11, in
load_entry_point('samsungctl==0.7.1+1', 'console_scripts', 'samsungctl')()
File "build/bdist.linux-armv7l/egg/samsungctl/main.py", line 110, in main
File "build/bdist.linux-armv7l/egg/samsungctl/remote.py", line 11, in init
File "build/bdist.linux-armv7l/egg/samsungctl/remote_websocket.py", line 86, in init
RuntimeError: Auth Failure

If I delete the remote authorisations from the TV's device list, then it succeeds again - but just the once.
So it seems like there seems to be something missing after the first successful connection that needs to be saved and reused for subsequent connections.

not odd..
do me a favor. run it again with the -vvvv cli switch. paste the output to me please.

OK i pushed a new version to that branch. I removed raising an exception of the receive timer expires. I also changed the authorization timeout to 30 seconds. and i added a bunch of additional logging.

Right, progress!
Now it succeeds on subsequent attempts, but the TV is prompting for authorisation every time. This is despite the TV being set to "Access Notification: Off".
Here's the output for the first attempt and two subsequent ones:

[09:10:32] openhabian@openHABianPi:~/samsungctl-kdschlosser/samsungctl$ samsungctl -vvvv --host <IP_ADDRESS> KEY_GUIDE
using saved token: 15716987
Websocket Connection Opened
incoming message: {"data":{"clients":[{"attributes":{"name":"c2Ftc3VuZ2N0bA==","token":"15716987"},"connectTime":1545469865341,"deviceName":"c2Ftc3VuZ2N0bA==","id":"a13c8910-9c46-4057-9f53-5d6872818ac1","isHost":false}],"id":"a13c8910-9c46-4057-9f53-5d6872818ac1","token":"21129284"},"event":"ms.channel.connect"}
new token data: <IP_ADDRESS>:21129284
Access granted.
Sending control command: KEY_GUIDE
Receive timer timed out
Websocket Connection Closed
[09:11:10] openhabian@openHABianPi:~/samsungctl-kdschlosser/samsungctl$ !!
samsungctl -vvvv --host <IP_ADDRESS> KEY_GUIDE
using saved token: 15716987
Websocket Connection Opened
incoming message: {"data":{"clients":[{"attributes":{"name":"c2Ftc3VuZ2N0bA==","token":"15716987"},"connectTime":1545469884776,"deviceName":"c2Ftc3VuZ2N0bA==","id":"662b3fb5-5291-4a35-b592-46a4ab783c65","isHost":false}],"id":"662b3fb5-5291-4a35-b592-46a4ab783c65","token":"17019686"},"event":"ms.channel.connect"}
new token data: <IP_ADDRESS>:17019686
Access granted.
Sending control command: KEY_GUIDE
Receive timer timed out
Websocket Connection Closed
[09:11:34] openhabian@openHABianPi:~/samsungctl-kdschlosser/samsungctl$ !!
samsungctl -vvvv --host <IP_ADDRESS> KEY_GUIDE
using saved token: 15716987
Websocket Connection Opened
incoming message: {"data":{"clients":[{"attributes":{"name":"c2Ftc3VuZ2N0bA==","token":"15716987"},"connectTime":1545469904397,"deviceName":"c2Ftc3VuZ2N0bA==","id":"dbcd923-946-4a4a-967e-8e89ce75a129","isHost":false}],"id":"dbcd923-946-4a4a-967e-8e89ce75a129","token":"59996395"},"event":"ms.channel.connect"}
new token data: <IP_ADDRESS>:59996395
Access granted.
Sending control command: KEY_GUIDE
Receive timer timed out

Websocket Connection Closed

OooOo there are 2 tokens...
check that out.

maybe I am grabbing the wrong token. it is using the saved token tho. I am not sure why it keeps on wanting to authorize the connection. I think I know where i messed up. I didn't think the token would refresh it's self each and every single time you connected. apparently it is. I know how to handle the issue tho. Give me a few minutes to fix it.
{
	"data": {
		"clients": [
			{
				"attributes":  {
					"name":"c2Ftc3VuZ2N0bA==",
					"token":"15716987"
				},
				"connectTime":1545469904397,
				"deviceName":"c2Ftc3VuZ2N0bA==",
				"id":"dbcd923-946-4a4a-967e-8e89ce75a129",
				"isHost":false
			}
		],
		"id":"dbcd923-946-4a4a-967e-8e89ce75a129",
		"token":"59996395"
	},
	"event":"ms.channel.connect"
}

OK i just pushed a new commit to that same branch. I believe i fixed the issue with it using the wrong token. It will automatically fix the token.txt file so there is no need for you to do anything. it will also grab the last stored token in the file. which will be the one from the last time you connected with the program. hopefully you should not see that authorization message on the TV again.

and the JSON data above is organized showing you the token you used to connect which is under the attributes section and then the new token being issued under the data section.. so it makes a wee bit more sence to me after staring at it for a bit.

Hmm.
No auth prompt on the second attempt, but no success either ... waits a long time and then returns auth failure:

samsungctl -vvvv --host <IP_ADDRESS> KEY_GUIDE
using saved token: &token=59996395
Websocket Connection Opened
incoming message: {"data":{"clients":[{"attributes":{"name":"c2Ftc3VuZ2N0bA==","token":"59996395"},"connectTime":1545479841553,"deviceName":"c2Ftc3VuZ2N0bA==","id":"7259c24-6ee3-4ff6-bad7-43185c82af","isHost":false}],"id":"7259c24-6ee3-4ff6-bad7-43185c82af","token":"14604647"},"event":"ms.channel.connect"}
new token: <IP_ADDRESS>:14604647
Access granted.
Sending control command: KEY_GUIDE
Receive timer timed out
Websocket Connection Closed
[11:57:29] openhabian@openHABianPi:~/samsungctl-kdschlosser/samsungctl$ !!
samsungctl -vvvv --host <IP_ADDRESS> KEY_GUIDE
using saved token: &token=14604647
Websocket Connection Opened
incoming message: {"data":{"clients":[{"attributes":{"name":"c2Ftc3VuZ2N0bA==","token":"14604647"},"connectTime":1545479863360,"deviceName":"c2Ftc3VuZ2N0bA==","id":"5ab284b7-da14-4726-a2a7-e556ee15c3e7","isHost":false}],"id":"5ab284b7-da14-4726-a2a7-e556ee15c3e7"},"event":"ms.channel.connect"}
Websocket Connection Closed
Traceback (most recent call last):
File "/usr/local/bin/samsungctl", line 11, in
load_entry_point('samsungctl==0.7.1+1', 'console_scripts', 'samsungctl')()
File "build/bdist.linux-armv7l/egg/samsungctl/main.py", line 110, in main
File "build/bdist.linux-armv7l/egg/samsungctl/remote.py", line 11, in init
File "build/bdist.linux-armv7l/egg/samsungctl/remote_websocket.py", line 102, in init
RuntimeError: Auth Failure

hmmm... that looks like a timing issue. let me check something.

yeah I see the thing that is going on. I had the placement of the mechanism that stops that authentication wait at the wrong level.
if a proper token is supplied then the TV will respond with ms.channel.connect but no new token. I had to move the stopping of the timer down one level in the code block.
I already pushed the fix to that branch. This should be the last one for the websocket ssl.
I have to now make some changes that will allow the program to dynamically set between using the non ssl and the ssl variant but it is looking like this works.

and that is kinda crappy also that the TV does not send a response for the key presses so we are going to have to rely on a preset timeout period.

OK so it is now time to close this issue. The websocket portion of things should be working fine now.
This issue is getting to be a bother to scroll all the way down to enter a comment any way

@davidgurr @kdschlosser
Are you up for some real debugging ?
Samsung TVs can be fairly easy be put in a debug mode, described here (https://developer.samsung.com/tv/dev...apps/debugging)
What you would need is:
a/ IP address of your laptop or desktop that you plan to use to capture some logs
b/ IP address of the TV
If you look at the instructions: go to apps, enter 12345 and done. That should cause a pop up to appear. There you turn on debug and enter the IP address of your laptop/desktop. Click OK, boot TV
Now you go to your desktop and you open a browser and enter <TV_IP_Address>:8001 hit enter (wait about a minute after reboot). This should show you the Multiscreen Service settings. At the bottom set logging to Silly, now click on View Logs and you should see what is happening.
Now you open the SmartThings app on your phone (make sure it was not active when you began logging because we want to see what it does when it registers with the TV) and change some input settings, change channels , this should cause log entries. Capture that logging info (select all, copy, paste to file).
Set logging back to Error.
Repeat the same thing on your TV, go to apps, enter 12345, set debug off.
Thoughts?
Dirk

@Murph24
bummer. I assume you placed it in Silly logging mode?
If you change say input source or a channel with your regular remote, do you see SmartThings update immediately? Do you see log entries when you try that?

@dcorsus yes both were silly mode logging

@Murph24
missed your attachment, looking at it now. I think it is soo large because whole images (binaries) are included in log. Thanks!!!!!!!!!!!!

@Murph24
The log you had attached, was that log entries from SmartView? The log is quite a treasure-trove for app information and there is some hint on how icon info is sent back, just don't know what exactly tickled it but it may be returned with "event" : "ed.apps.icon".
So if you use SmartThings, you see nothing at all showing up in the log? What if you change input sources or channels with a regular remote while SmartView and SmartThings are connected? Nothing?

@dcorsus yes the .txt was from SmartView.   I don’t see anything in the log when I send commands via SmartThings.  I also don’t see any log entries from just using the regular remote.
That log is in reverse order so first log item is the last line. Looks like the app events fire after the command:

@dcorsus yes the .txt was from SmartView. I don’t see anything in the log when I send commands via SmartThings. I also don’t see any log entries from just using the regular remote.
I think that log is in reverse order maybe?....so first log item is the last line. Looks like the app events fire after the command: "uri : /api/v2/applications/ExtraService, method: GET"
DEBUG	"## getApplication ##"	"timestamp:<PHONE_NUMBER>295, file: TizenDevice.cpp, func: getApplication : 411"
DEBUG	"getApplication called!! id=ExtraService"	"timestamp:<PHONE_NUMBER>295, file: ApiV2.cpp, func: RestHandler : 155"
DEBUG	"uri : /api/v2/applications/ExtraService, method: GET"	"timestamp:<PHONE_NUMBER>295, file: ApiV2.cpp, func: RestHandler : 115"

Indeed in reverse order. Bummer there is nothing in this log , so Smartthings isn't using multiscreen functions URGGHHH

@davidgurr