kdschlosser / samsungctl

Remote control Samsung televisions via a TCP/IP connection
MIT License
150 stars 34 forks source link

Impossible to send command to TV #40

Closed andreas-bulling closed 5 years ago

andreas-bulling commented 5 years ago

Hi,

thanks a lot for this updated library. I am playing around with it to hopefully be able to eventually integrate it with HA.

However, I can't send any commands to my Samsung TV (UE50J6250, firmware 1530). I am using websocket and tried both port 8001 and 8002 but nothing happens. I also don't see the authentication popup which suggests that the connection is actually not established properly.

Anything I can do to debug this / help with to make it easier for you to figure out why it's not working?

jnimmo commented 5 years ago

Firstly ensuring you're running the latest version of the code and it isn't running an old version of samsungctl.. Also showing the commands you're trying to use

andreas-bulling commented 5 years ago

I am using a fresh checkout from the repository half an hour ago:

samsungctl --version
samsungctl 0.8.0b

I am trying the following: samsungctl --host $IP --method websocket --port 8001 KEY_HOME

raydog153 commented 5 years ago

Have you validated port 8001 is open on your tv? What is the output?

arsaboo commented 5 years ago

Also, shouldn't the command be something like (your are missing the remoteCmd) : samsungctl --host 192.168.2.252 --method websocket --port 8002 --name remoteCmd KEY_POWER

kdschlosser commented 5 years ago

H and J series TVs use a funky encrypted websocket. At this point in time this library does not support H and J series TV. We are working on getting it added.

If you clone this branch and give it a go. See what happens.

https://github.com/kdschlosser/samsungctl/tree/H_J_series_TVs?files=1

You need to use

--method encrypted

In order to run the proper websocket type for your TV.

I do not know if that branch will work or not. You are the first person that might have a compatible TV. Let me know if it works or not. If you get any errors please paste the entire output to a comment I need to see all of the information

andreas-bulling commented 5 years ago

@kdschlosser I tried the mentioned branch, here is the result:

python -m samsungctl --method encrypted --host $IP --interactive                                                     (H_J_series_TVs)
Traceback (most recent call last):
  File "/usr/local/Cellar/python@2/2.7.15_1/Frameworks/Python.framework/Versions/2.7/lib/python2.7/runpy.py", line 174, in _run_module_as_main
    "__main__", fname, loader, pkg_name)
  File "/usr/local/Cellar/python@2/2.7.15_1/Frameworks/Python.framework/Versions/2.7/lib/python2.7/runpy.py", line 72, in _run_code
    exec code in run_globals
  File "/Users/andreas/Desktop/samsungctl/samsungctl/__main__.py", line 206, in <module>
    main()
  File "/Users/andreas/Desktop/samsungctl/samsungctl/__main__.py", line 181, in main
    with Remote(config) as remote:
  File "samsungctl/remote.py", line 16, in __init__
    self.remote = RemoteWebsocketEncrypted(config)
  File "samsungctl/remote_encrypted.py", line 73, in __init__
    self.open()
  File "samsungctl/remote_encrypted.py", line 134, in open
    if not self.is_pin_page_open:
  File "samsungctl/remote_encrypted.py", line 118, in is_pin_page_open
    response = requests.get(url)
  File "/usr/local/lib/python2.7/site-packages/requests/api.py", line 72, in get
    return request('get', url, params=params, **kwargs)
  File "/usr/local/lib/python2.7/site-packages/requests/api.py", line 58, in request
    return session.request(method=method, url=url, **kwargs)
  File "/usr/local/lib/python2.7/site-packages/requests/sessions.py", line 494, in request
    prep = self.prepare_request(req)
  File "/usr/local/lib/python2.7/site-packages/requests/sessions.py", line 437, in prepare_request
    hooks=merge_hooks(request.hooks, self.hooks),
  File "/usr/local/lib/python2.7/site-packages/requests/models.py", line 305, in prepare
    self.prepare_url(url, params)
  File "/usr/local/lib/python2.7/site-packages/requests/models.py", line 373, in prepare_url
    raise InvalidURL(*e.args)
requests.exceptions.InvalidURL: Failed to parse: $IP:None
kdschlosser commented 5 years ago
-m samsungctl --method encrypted --host $IP --interactive

what is $IP???

it is stating invalid IP is because whatever $IP is it's not the IP address of the TV.

andreas-bulling commented 5 years ago

I just replaced the actual IP with a placeholder for posting here. It was an actual IP

kdschlosser commented 5 years ago

Oh ok.

andreas-bulling commented 5 years ago

Anything to be learned from the output? Can I provide any other help?

kdschlosser commented 5 years ago

I am not sure what you are putting in on the command line for an IP address. it should be something like this 192.168.1.1 because that error is not being generated by samsungctl. it is being generated by the requests library and it is telling us that there is something wrong with the URL that is being passed to it. I will double check the code to make sure there isn't an issue when i turn the IP into a URL.

kdschlosser commented 5 years ago

this is the template being used

http://{ip}:{port}/ws/apps/CloudPINPage

I am replacing the {ip} with the IP provided by you and 8080 is getting placed where {port} is so the URL should be correct so long as a proper IP is being supplied.

dseifert commented 5 years ago

The final line in the error was "Failed to parse: $IP:None". Assuming @andreas-bulling replaced the actual IP as he said and it didn't just get passed in as "$IP", the problem seems to be that port substitution did not work as it said ":None".

dseifert commented 5 years ago

@kdschlosser couldn't the issue be in these lines?

url = PIN_URL_OPEN.format(
            ip=self.config["host"],
            http_port=self.config["http_port"],
        )

I don't see http_port defined anywhere, so accessing it should give you the default of None.

andreas-bulling commented 5 years ago

Yes, I of course had a proper IP address given there and no port. I can try adding a port explicitly but if none is provided the script should IMHO use a default...

UPDATE: I added a port explicitly but it still tries to connect to $IP:None

UPDATE2: There are multiple self.config["http_port"] references in the file. Those should read self.config["port"] I believe

andreas-bulling commented 5 years ago

Alright, I replaced the http_port entries and tried to connect to port 8001 on my TV. It shows a PIN but when I try to enter it in the console I hit another error:

python -m samsungctl --method encrypted --host 192.168.178.60 --port 8001 --interactive                                        (H_J_series_TVs✱)
Enter Pin from TV:3745
Traceback (most recent call last):
  File "/usr/local/Cellar/python@2/2.7.15_1/Frameworks/Python.framework/Versions/2.7/lib/python2.7/logging/__init__.py", line 868, in emit
    msg = self.format(record)
  File "/usr/local/Cellar/python@2/2.7.15_1/Frameworks/Python.framework/Versions/2.7/lib/python2.7/logging/__init__.py", line 741, in format
    return fmt.format(record)
  File "/usr/local/Cellar/python@2/2.7.15_1/Frameworks/Python.framework/Versions/2.7/lib/python2.7/logging/__init__.py", line 465, in format
    record.message = record.getMessage()
  File "/usr/local/Cellar/python@2/2.7.15_1/Frameworks/Python.framework/Versions/2.7/lib/python2.7/logging/__init__.py", line 329, in getMessage
    msg = msg % self.args
TypeError: not all arguments converted during string formatting
Logged from file remote_encrypted.py, line 99
step 1 response: <!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title>404 : Not Found</title>

    <link rel="stylesheet" href="/resources/css/bootstrap.min.css">
    <script src="/resources/js/bootstrap.min.js"></script>

</head>
<body>

<div class="container-fluid">
    <div class="page-header">
        <h1>Oops!</h1>
    </div>
    <div class="panel panel-default">
        <div class="panel-heading">404 : Page Not Found</div>
        <div class="panel-body">
            These are not the droids your looking for....
        </div>
    </div>

</div>

</body>
</html>
Traceback (most recent call last):
  File "/usr/local/Cellar/python@2/2.7.15_1/Frameworks/Python.framework/Versions/2.7/lib/python2.7/logging/__init__.py", line 868, in emit
    msg = self.format(record)
  File "/usr/local/Cellar/python@2/2.7.15_1/Frameworks/Python.framework/Versions/2.7/lib/python2.7/logging/__init__.py", line 741, in format
    return fmt.format(record)
  File "/usr/local/Cellar/python@2/2.7.15_1/Frameworks/Python.framework/Versions/2.7/lib/python2.7/logging/__init__.py", line 465, in format
    record.message = record.getMessage()
  File "/usr/local/Cellar/python@2/2.7.15_1/Frameworks/Python.framework/Versions/2.7/lib/python2.7/logging/__init__.py", line 329, in getMessage
    msg = msg % self.args
TypeError: not all arguments converted during string formatting
Logged from file crypto.py, line 59
Traceback (most recent call last):
  File "/usr/local/Cellar/python@2/2.7.15_1/Frameworks/Python.framework/Versions/2.7/lib/python2.7/logging/__init__.py", line 868, in emit
    msg = self.format(record)
  File "/usr/local/Cellar/python@2/2.7.15_1/Frameworks/Python.framework/Versions/2.7/lib/python2.7/logging/__init__.py", line 741, in format
    return fmt.format(record)
  File "/usr/local/Cellar/python@2/2.7.15_1/Frameworks/Python.framework/Versions/2.7/lib/python2.7/logging/__init__.py", line 465, in format
    record.message = record.getMessage()
  File "/usr/local/Cellar/python@2/2.7.15_1/Frameworks/Python.framework/Versions/2.7/lib/python2.7/logging/__init__.py", line 329, in getMessage
    msg = msg % self.args
TypeError: not all arguments converted during string formatting
Logged from file crypto.py, line 62
Traceback (most recent call last):
  File "/usr/local/Cellar/python@2/2.7.15_1/Frameworks/Python.framework/Versions/2.7/lib/python2.7/runpy.py", line 174, in _run_module_as_main
    "__main__", fname, loader, pkg_name)
  File "/usr/local/Cellar/python@2/2.7.15_1/Frameworks/Python.framework/Versions/2.7/lib/python2.7/runpy.py", line 72, in _run_code
    exec code in run_globals
  File "/Users/andreas/Desktop/samsungctl/samsungctl/__main__.py", line 206, in <module>
    main()
  File "/Users/andreas/Desktop/samsungctl/samsungctl/__main__.py", line 181, in main
    with Remote(config) as remote:
  File "samsungctl/remote.py", line 16, in __init__
    self.remote = RemoteWebsocketEncrypted(config)
  File "samsungctl/remote_encrypted.py", line 73, in __init__
    self.open()
  File "samsungctl/remote_encrypted.py", line 146, in open
    self.pin = pin
  File "samsungctl/remote_encrypted.py", line 110, in pin
    self.run_forever()
  File "samsungctl/remote_encrypted.py", line 171, in run_forever
    self.pin
  File "samsungctl/pySmartCrypto/crypto.py", line 68, in generate_server_hello
    logger.debug('crypto: aes encrypted: ', encrypted.hex())
AttributeError: 'str' object has no attribute 'hex'
andreas-bulling commented 5 years ago

Found some links related to this problem: https://github.com/Ape/samsungctl/issues/22 https://github.com/timelery/Samsung-RemoteControl

UPDATE: I replaced too many instances of http_port - some port settings need to be 8080 as it seems from one of the above links. I can get rid of the 404 error but now I see

Enter Pin from TV:1568
Traceback (most recent call last):
  File "/usr/local/Cellar/python@2/2.7.15_1/Frameworks/Python.framework/Versions/2.7/lib/python2.7/logging/__init__.py", line 868, in emit
    msg = self.format(record)
  File "/usr/local/Cellar/python@2/2.7.15_1/Frameworks/Python.framework/Versions/2.7/lib/python2.7/logging/__init__.py", line 741, in format
    return fmt.format(record)
  File "/usr/local/Cellar/python@2/2.7.15_1/Frameworks/Python.framework/Versions/2.7/lib/python2.7/logging/__init__.py", line 465, in format
    record.message = record.getMessage()
  File "/usr/local/Cellar/python@2/2.7.15_1/Frameworks/Python.framework/Versions/2.7/lib/python2.7/logging/__init__.py", line 329, in getMessage
    msg = msg % self.args
TypeError: not all arguments converted during string formatting
Logged from file remote_encrypted.py, line 99
step 1 response: {"auth_data":""}
andreas-bulling commented 5 years ago

I hard-coded a device id (not good if it's empty as it's use during the encryption handshake) and commented out most of the logger calls given that these don't seem to work...

Now I see this:

Enter Pin from TV:1609 step 1 response: {"auth_data":""}

Traceback (most recent call last): File "/usr/local/Cellar/python@2/2.7.15_1/Frameworks/Python.framework/Versions/2.7/lib/python2.7/runpy.py", line 174, in _run_module_as_main "main", fname, loader, pkg_name) File "/usr/local/Cellar/python@2/2.7.15_1/Frameworks/Python.framework/Versions/2.7/lib/python2.7/runpy.py", line 72, in _run_code exec code in run_globals File "/Users/andreas/Desktop/samsungctl/samsungctl/main.py", line 206, in main() File "/Users/andreas/Desktop/samsungctl/samsungctl/main.py", line 181, in main with Remote(config) as remote: File "samsungctl/remote.py", line 16, in init self.remote = RemoteWebsocketEncrypted(config) File "samsungctl/remote_encrypted.py", line 73, in init self.open() File "samsungctl/remote_encrypted.py", line 146, in open self.pin = pin File "samsungctl/remote_encrypted.py", line 110, in pin self.run_forever() File "samsungctl/remote_encrypted.py", line 180, in run_forever GeneratorServerHello=hex(int(server_hello)).upper() ValueError: invalid literal for int() with base 10: '\x01\x02'

kdschlosser commented 5 years ago

OOOO crap. I need to fix the websocket end of this branch. I forgot there is a problem with the websocket library. I need to remove the use of WebsocketApp.

the logging does work I need to add a line to it to make it print out what is going on.

and this branch was not set up to be run from the command line as of yet. It needs a lot of work I know. I will put some time into it today. I will make a new branch and add all of the encryption parts to it.

It is going to take me a a couple of days to get it done. I am in the middle of installing 3 furnaces into my house. and adding new ducts and gas lines. Its a pretty large project. I will do my best to get it done as fast as I can. But my time is going to be very limited over the next week or so.

I see you are using python 2.x so I will make it work for python 2 and after we know it is working 100% I will dink around with making it also work in python 3.

andreas-bulling commented 5 years ago

Thanks a lot @kdschlosser, your work is most highly appreciated. Let me know if I can be of any help with the testing. I should have some time over the weekend.

BTW: If you/we manage to make this work, this could be big - there is a huge demand for support for these lines of TVs, e.g. in home automation.

raydog153 commented 5 years ago

I hit several of these issues myself and worked thru them. I have a lot more little changes that I needed to make to get to where I am...and am able to pair but not get any farther ATM.

This is related to #31. Willing to help out any way I can...

kdschlosser commented 5 years ago

@andreas-bulling No worries m8. I do know how important it is to have a TV integrated into your HA. Thee library in it's current state works for all TV's from 2008 to current except for 2 years. i believe it is 2014 and 2015 the TV's that have H or J in the model number. Some time in 2013 someone decided to see how hard it would be to get the voice controlled TVs to start listening and to intercept that audio. short story is they did it. and they published an article on Samsung having no kind of security. Samsung went all kinds of bonkers. and they locked down their whole API to everything. 2014 model year devices was the first year to have this new security put into place. it stayed like this for 2 years. When all the static about not having tighter security simmered down they loosened up some. You happen to have one of the TV's made during that 2 years. So it is going to take some to get it working correctly.

@raydog153 Would you be willing to share the changes you have made with me?

raydog153 commented 5 years ago

I would be glad to share the changes...had tried to create PR branch but was unable too.

kdschlosser commented 5 years ago

zip it up and attach it to a comment.

raydog153 commented 5 years ago

Here you go...some of the logic change was for my model, can skip those parts

samsungctl.zip

p3g4asus commented 5 years ago

This is my TV (output of http://192.168.25.32:8001/api/v2/):

{
  "id": "068e7780-006e-1000-bc6f-f877b8a47bf1",
  "name": "[TV]Samsung LED55",
  "version": "2.0.24",
  "device": {
    "type": "Samsung SmartTV",
    "duid": "068e7780-006e-1000-bc6f-f877b8a47bf1",
    "model": "14_X14_BT",
    "modelName": "UE55H6400",
    "description": "Samsung TV RCR",
    "networkType": "wireless",
    "ssid": "OpenWrt2",
    "ip": "192.168.25.32",
    "firmwareVersion": "Unknown",
    "name": "[TV]Samsung LED55",
    "id": "068e7780-006e-1000-bc6f-f877b8a47bf1",
    "udn": "068e7780-006e-1000-bc6f-f877b8a47bf1",
    "resolution": "1920x1080",
    "countryCode": "IT",
    "msfVersion": "2.0.24",
    "smartHubAgreement": "true",
    "developerMode": "0",
    "developerIP": "0.0.0.0"
  },
  "type": "Samsung SmartTV",
  "uri": "http://192.168.25.32:8001/api/v2/"
}

I made some tests using raydog153 zip with some modifications on main.py to add some command line arguments. This is the detail of the changes made. After

    parser.add_argument(
        "--port",
        type=int,
        help="TV port number (TCP)"
    )

I added

    parser.add_argument(
        "--http_port",
        type=int,
        help="TV port number (TCP)"
    )
    parser.add_argument(
        "--user_id",
        default="0548",
        help="User id"
    )
    parser.add_argument(
        "--device_id",
        default="7890",
        help="Device id"
    )

In the TV screen I see two differently shaped windows that show different pin numbers. But the windows are one in front of the other so I can read only the PIN displayed in the front window. This front window disappears when I insert the displayed pin and press enter in the samsungctl console. The other window remains and closes after its countdown reaches zero. I think thet only one of the two windows is supposed to appear and not both. From the test output it seems I am getting user_id_len = 0 Can you provide the documentation that you are following to implement this comunication protocol so that I can help you in development? I have the hardware to test so it should be much simpler and quicker for me. Thanks for your work. The details of the test done follow: Issued command line:

python -m samsungctl -vvv --host 192.168.25.32 --method encrypted --http_port 8080 --name samsungctl KEY_MUTE

Stdout output:

TRACE: request GET URL(200): http://192.168.25.32:8080/ws/apps/CloudPINPage
TRACE: request CONTENT=<?xml version="1.0" encoding="UTF-8"?><service xmlns="urn:dial-multiscreen-org:schemas:dial" xmlns:atom="http://www.w3.org/2005/Atom"><name>CloudPINPage</name><options allowStop="true"/><state>running</state><atom:link rel="run" href="run"/></service>
pairing step 1: http://192.168.25.32:8080/ws/pairing?step=0&app_id=12345&device_id=7890&type=0
TRACE: request GET URL(200): http://192.168.25.32:8080/ws/pairing?step=0&app_id=12345&device_id=7890&type=0
TRACE: request CONTENT={"auth_data":""}

Enter Pin from TV:3620
crypto: pin hash: b65cfa72d8975ff059585739e4959236300da382
crypto: aes: b65cfa72d8975ff059585739e4959236
crypto: aes encrypted: d0c0bb4bb1f7c534d0c1124bf7e3d1239ff109c0b1aae725482221de7fca189b9220eb55658a27fa0a4705325f71ededbee5d919c993495a594d86baaeaafc2881116c02da47847ddbd0cbbc1dd068d2d8795bb1beef4df725d37e6b8fbf72225630c672175c379ae0acd0f82385c8535806df0490aeeb984cd5e65a71e39889
crypto: aes swapped: 00f0a0643b6ce303f1f9eb5239c4d9dd547badced32c04c2763318e2f345281b1731fc293f02f102ced35bce5db2809ccd5e97afd8020d87b2eddc2fda4ec5e6c8c0f2ad5391628e0b49aeced1415201bc9b6431333edaff17ba46ffd27260f0524c3a1517b194a298a4964ed8aae483cfcfdcd785564562610fb851d7e222a9
crypto: data buffer: 000000043035343800f0a0643b6ce303f1f9eb5239c4d9dd547badced32c04c2763318e2f345281b1731fc293f02f102ced35bce5db2809ccd5e97afd8020d87b2eddc2fda4ec5e6c8c0f2ad5391628e0b49aeced1415201bc9b6431333edaff17ba46ffd27260f0524c3a1517b194a298a4964ed8aae483cfcfdcd785564562610fb851d7e222a9
crypto: data hash: 6b954d74f0a22e5934f0c2301644a5dee248a6ac
server hello: 0102000000000000000088000000043035343800f0a0643b6ce303f1f9eb5239c4d9dd547badced32c04c2763318e2f345281b1731fc293f02f102ced35bce5db2809ccd5e97afd8020d87b2eddc2fda4ec5e6c8c0f2ad5391628e0b49aeced1415201bc9b6431333edaff17ba46ffd27260f0524c3a1517b194a298a4964ed8aae483cfcfdcd785564562610fb851d7e222a90000000000
data hash: 6b954d74f0a22e5934f0c2301644a5dee248a6ac
aes key: b65cfa72d8975ff059585739e4959236
pairing step 2: http://192.168.25.32:8080/ws/pairing?step=1&app_id=12345&device_id=7890
TRACE: request POST URL(200): http://192.168.25.32:8080/ws/pairing?step=1&app_id=12345&device_id=7890
TRACE: request PAYLOAD: {"auth_Data": {"auth_type": "SPC", "GeneratorServerHello": "0102000000000000000088000000043035343800F0A0643B6CE303F1F9EB5239C4D9DD547BADCED32C04C2763318E2F345281B1731FC293F02F102CED35BCE5DB2809CCD5E97AFD8020D87B2EDDC2FDA4EC5E6C8C0F2AD5391628E0B49AECED1415201BC9B6431333EDAFF17BA46FFD27260F0524C3A1517B194A298A4964ED8AAE483CFCFDCD785564562610FB851D7E222A90000000000"}}
TRACE: request CONTENT={"auth_data":"{\"auth_type\":\"SPC\",\"request_id\":\"4\",\"GeneratorClientHello\":\"019A000000000000000000\"}"}

step 2 response: {"auth_data":"{\"auth_type\":\"SPC\",\"request_id\":\"4\",\"GeneratorClientHello\":\"019A000000000000000000\"}"}

client hello: 019A000000000000000000
request id: 4
crypto: client hello: 019a000000000000000000
crypto: data_hash: 6b954d74f0a22e5934f0c2301644a5dee248a6ac
crypto: dest: 6b954d74f0a22e5934f0c2301644a5dee248a6ac
crypto: user id:
crypto: pEncWBGx:
crypto: pEncGx:
crypto: pGx:
Traceback (most recent call last):
  File "C:\Python27\lib\runpy.py", line 174, in _run_module_as_main
    "__main__", fname, loader, pkg_name)
  File "C:\Python27\lib\runpy.py", line 72, in _run_code
    exec code in run_globals
  File "D:\Dati\tmp\sam3\samsungctl\__main__.py", line 289, in <module>
    main()
  File "D:\Dati\tmp\sam3\samsungctl\__main__.py", line 257, in main
    with Remote(config, log_level) as remote:
  File "samsungctl\remote.py", line 23, in __init__
    self.remote = RemoteWebsocketEncrypted(config)
  File "samsungctl\remote_encrypted.py", line 74, in __init__
    self.open()
  File "samsungctl\remote_encrypted.py", line 160, in open
    self.pin = pin
  File "samsungctl\remote_encrypted.py", line 115, in pin
    self.run_forever()
  File "samsungctl\remote_encrypted.py", line 232, in run_forever
    self.config["user_id"]
  File "samsungctl\pySmartCrypto\crypto.py", line 139, in parse_client_hello
    bn_pgx = int(codecs.encode(pgx, 'hex'), 16)
ValueError: invalid literal for int() with base 16: ''
kdschlosser commented 5 years ago

there is no documentation. we are flying solo on this.

kdschlosser commented 5 years ago

and you also have the same issue that @raydog153 has.. I believe the TV model might be an issue. UE55H6400

I believe the "Smart" TV models do not start until 7000. I may not be correct in this assessment of what models are going to support the IP control.

I would suggest trying this https://github.com/eclair4151/SmartCrypto and see if it works. What is added in samsungctl is a modified version of that code to be python 2 compatible and also not to be a single use arrangement.

If that code works then I will go back to step one and add the code in a different manner that would not make so many changes to it.

p3g4asus commented 5 years ago

Thank you very much. This evening I will try eclair4151 script. I will report here my results.

kdschlosser commented 5 years ago

@p3g4asus ok cool. If it works properly then I will add the code with minimal changes to it.

are you familiar with getting the XML files from the TV for UPNP??? I am interested in seeing what the available UPNP functions and classes are. I know that with the legacy TV's (pre 2014) the amount of added control is astounding. I know that Samsung over time as removed bits and pieces of UPNP I would be curious to see what your TV has available to it. The newest TV's offer DLNA via UPNP and a few other functions like setting the aspect ratio. It is a small number of available functions compared to the Legacy TV's. and Since your TV is that middle point I would help me a lot to be able to have the XML files so I can code in better UPNP functionality.

p3g4asus commented 5 years ago

I tested eclair4151's script over lunch time. I can confirm that it is working for my TV like a charm. My question now is: what should be saved to issue a further command without having to reinsert the pin? Do you know what steps of the pairing process can be avoided having saved "authorization token" and what exactly the authorization token is? @kdschlosser Unfortunately I am not familiar with UPNP-XML capabilities downloading. But if you point me to a tutorial I will definitely do it, if it can help and speed up development. Thanks again Edit: I don't know if it can be useful but here is the successfull execution log

> py -3 smartcrypto.py
Current state: stopped
Pin NOT on TV
Please enter pin from tv: 7909
Got pin: '7909'

AES key: 4b186c08fa1d726270bc93e7a8c874ea
AES encrypted: 81f9c45ee7b047d91b682dd3f10074370b44f385145a3bcf1d80ff6dc6cba4e2e8c484794b7e69c09b351c8b0efd9af26740736274e4dc0b3b03cf7bce2c49617fe53f21f4e2b61cfbc36cb734dd06536212a1b07b395f3b2dd30ba330ebf19ae406a486ea13a225ba4f98589ffd8b9860aff2907b1350fe7b0d343c740faa43
AES swapped: 5994a2528f4e64b9910c43d6d99b7a6965266b178d416186fb5d3ae782cac6a2dbd15f8aa00fd74d6dd162d5e75f1e3e8acaa927d020a723e7095337accc5fe17c0e3ff9dc37577a5c0c141e1f3dae1b595bbd082cfe825b102cb6c234295dc45851101bfa64dc5d4f070dfd2ecf27288b8604afbd5d17fe9c1c8db7a8e92d86
data buffer: 000000063635343332315994A2528F4E64B9910C43D6D99B7A6965266B178D416186FB5D3AE782CAC6A2DBD15F8AA00FD74D6DD162D5E75F1E3E8ACAA927D020A723E7095337ACCC5FE17C0E3FF9DC37577A5C0C141E1F3DAE1B595BBD082CFE825B102CB6C234295DC45851101BFA64DC5D4F070DFD2ECF27288B8604AFBD5D17FE9C1C8DB7A8E92D86
hash: 7ed1947b1717ca42cb1bf7bb2cf218e5d202d50b
secondStepResponse: {"auth_data":"{\"auth_type\":\"SPC\",\"request_id\":\"0\",\"GeneratorClientHello\":\"010100000000000000009E0000000636353433323118FB6E7777A3E6DC283225C627D205DB953CF7766C384B83DE7452709159BA4A59FF9859FE4B3110FD8E66E677CFEF822DEFF6E4B7E065F5BC2038881BB7AB510F137FA48190B1D76E375A3376B8C49C8D146F1181E5D5D07A1CF2544B4C9EFE9F613304FE573478A658804F48D1C7F58C0118C2A9097D12AAC0C3745C1C1A0E4DD321CDFE77B0E90B888975933E6EEA4675CF370000000000\"}"}

thirdLen: 138
hello: 010100000000000000009e0000000636353433323118fb6e7777a3e6dc283225c627d205db953cf7766c384b83de7452709159ba4a59ff9859fe4b3110fd8e66e677cfef822deff6e4b7e065f5bc2038881bb7ab510f137fa48190b1d76e375a3376b8c49c8d146f1181e5d5d07a1cf2544b4c9efe9f613304fe573478a658804f48d1c7f58c0118c2a9097d12aac0c3745c1c1a0e4dd321cdfe77b0e90b888975933e6eea4675cf370000000000
dest: 0000000636353433323118fb6e7777a3e6dc283225c627d205db953cf7766c384b83de7452709159ba4a59ff9859fe4b3110fd8e66e677cfef822deff6e4b7e065f5bc2038881bb7ab510f137fa48190b1d76e375a3376b8c49c8d146f1181e5d5d07a1cf2544b4c9efe9f613304fe573478a658804f48d1c7f58c0118c2a9097d12aac0c3745c1c1a0e7ed1947b1717ca42cb1bf7bb2cf218e5d202d50b
userId: 654321
pEncWBGx: 18fb6e7777a3e6dc283225c627d205db953cf7766c384b83de7452709159ba4a59ff9859fe4b3110fd8e66e677cfef822deff6e4b7e065f5bc2038881bb7ab510f137fa48190b1d76e375a3376b8c49c8d146f1181e5d5d07a1cf2544b4c9efe9f613304fe573478a658804f48d1c7f58c0118c2a9097d12aac0c3745c1c1a0e
pEncGx: 822fee9c8f2a9c9bb6d31fae6ebbf94f5f1af15173b418c886001d1a88d5d2c93f4aaaaeb9c6d4d2b76f145ef839ea2054e963cb96806c5cd9d4164180682b56a1b33047ebe1e2098dd69a2ed54c668d0ebd7a29026ae97153d9746bc4efba9adfe705dffdb5e1259c83ec8e7b5e482bf69291e858312c98c713263fd87ee2a7
pGx: a901b61a1ca799fa777fc33eb03a40ff9198bccce678c4d8a3e2c7e01f523fbac1f88b091fd6e8e308e8f11b1eeda23315ab26bf544cca25cba3a765989611e764bd8dccf229ab06608381e6f7a0495ee6c4ed290dee39e3e0b2794592d74010615f3c7415705495c0ddfbcef4ad7b735bda7a72093ecfcf3dc0a34eb817dd42
secret: 9daca0fb33b6cb01d4c5af914d813ae414ddd6f1107545312b128942092c525f73e14b036af4cfec675ca02a3b0a62c389e3371dd9065b82cbf32faea7a191342f8c2130791cd576a8d3cb0c78684615d32782a8f558feba8cbb230d1e95df56bee5679d19a90c8c64abbdef640885c3fc950479b8b64a34ada03c1486a04061
hash2: 4dd321cdfe77b0e90b888975933e6eea4675cf37
secret2: 3635343332319daca0fb33b6cb01d4c5af914d813ae414ddd6f1107545312b128942092c525f73e14b036af4cfec675ca02a3b0a62c389e3371dd9065b82cbf32faea7a191342f8c2130791cd576a8d3cb0c78684615d32782a8f558feba8cbb230d1e95df56bee5679d19a90c8c64abbdef640885c3fc950479b8b64a34ada03c1486a04061
hash3: 4dd321cdfe77b0e90b888975933e6eea4675cf37
Pin OK :)

dest_hash: dbb73c57fad0769281cf0c9827a08d84565dea48
SKPrime: ca96bc5853835c65304c89006184d7807fdae1ab
SKPrimeHash: b739e9c26b14c73ef8dd46aafc108300fe77500e
ctx: f1017de9c2a982aac452638683b6aed1
Pin accepted :)

sessionId: 3
SessionID: 3
Authorization successfull :)

Attempting to send command to tv
ws://192.168.25.32:8000/socket.io/1/websocket/iG6zBiKYN-atshCfAPUK
raydog153 commented 5 years ago

@p3g4asus Since you have port 8001 open then you do not have the same issue as mine, please DO NOT use that zip file I have, it has changes specifically for my model and are untested to work Need someone like you to work thru the bugs here before my model can be tackled. You could try changing the code where 'type=0' to 'type=1' and that should solve the double pin issue. Also you need to use id/user_id of 12345 else things do not work.

The success logs may definitely help me thou. Your model is very close to mine. I get success but no port 800x to use, and not sure how to re-use the sessionId either. Nor is CloudPINPage ever reported as running for me.

andreas-bulling commented 5 years ago

what should I try with my TV/what would be helpful (if any)?

kdschlosser commented 5 years ago

OK sweet. it does work on your TV. I will start from the ground up again on the HJ branch. I am going to make less modifications to the code and I am not going to mess about with python 2.7 compatibility just yet.

kdschlosser commented 5 years ago

@p3g4asus

If you take a look at #39 I posted a library I made as well as use directions. I am going to add a feature to it to dump the SSDP packets and the XML files. this way I get a complete layout.

raydog153 commented 5 years ago

I am using python 2.7 but I think I also have 3 installed, just need to switch my default.

@kdschlosser I think it would be easier to not have that pairing_url method that is dynamic and increments the step. Just call each step explicitly so it is easier to follow the what the code is doing rather than having the code be DRY and more reusable at the moment. I think also better printout of the HTTP request/response with headers would help aid in debugging too.

Example...

    API URL GET http://localhost:8080/api.json?name=xzy
    API Request Headers: {"User-Agent"=>"Faraday v0.15.3", "accept"=>"application/xml,application/xhtml+xml,application/json,text/html,text/plain", "content-type"=>"application/x-www-form-urlencoded", "REQUEST_ID"=>"72f5c250-3cf4-4a8b-b192-0af7e387173e"}
    API Request Body:
    API Response Headers: {"server"=>"Apache-Coyote/1.1", "cache-control"=>"no-cache, no-store, max-age=0, must-revalidate", "pragma"=>"no-cache", "expires"=>"0", "x-xss-protection"=>"1; mode=block", "x-frame-options"=>"DENY", "x-content-type-options"=>"nosniff", "content-type"=>"application/json;charset=UTF-8", "transfer-encoding"=>"chunked", "date"=>"Sat, 22 Dec 2018 16:00:53 GMT", "connection"=>"close"}
    API Response Body( 582b ): { some json }
    API Completed 200 in 27
kdschlosser commented 5 years ago

I will mess about with it. I am going to start from the ground up it is going to be the easiest way. The hardest thing is how thee connection was originally coded. I have to get rid of the use of the globals.

kdschlosser commented 5 years ago

@p3g4asus i updated that UPNP library I am going to post directions in that issue

andreas-bulling commented 5 years ago

I also tried eclair4151's script and it worked perfectly for my TV - including sending commands to it!

python3 smartcrypto.py                                                                                                       (master✱)
Current state: stopped
Pin NOT on TV
Please enter pin from tv: 2555
Got pin: '2555'

AES key: bf60ee2fe3dbfa98308f3840c9ad4def
AES encrypted: 95f1d48efc9006c3712404ee75d504b52b4e4be620e53aa5f4a38cb7bb68c921c228b9469d70273e0dda1a42e5dff52c6d926b2e2dc035b128dc554bea43856d6db0845172f30752b1a29d802d225b6d8354a269cb2211ab756983d0ab39527dc9982c93bb1da8f44c172943df411d89eebf80c153606b85715758c9cc1c8728
AES swapped: 5c5d3d1406b26e4f992a8376050edc95ab5873fc191e87385a663571d59a4fa1e9385f27a3b25f2fd5e1bd9ba5519d7d2b6787ca4f488dcbf71247e7a57fe7f6ffef4d7d927f78e1d2d75d368a69adb7e30e79c9f19521cd455e46c39351f0b868851b623cc5aaa508820a35c7abe396ae11bdf25b6436a3ca13da53cbf21f22
data buffer: 000000063635343332315C5D3D1406B26E4F992A8376050EDC95AB5873FC191E87385A663571D59A4FA1E9385F27A3B25F2FD5E1BD9BA5519D7D2B6787CA4F488DCBF71247E7A57FE7F6FFEF4D7D927F78E1D2D75D368A69ADB7E30E79C9F19521CD455E46C39351F0B868851B623CC5AAA508820A35C7ABE396AE11BDF25B6436A3CA13DA53CBF21F22
hash: 1442614e19fb6dc44b02588ecd000bed2fb7d32f
secondStepResponse: {"auth_data":"{\"auth_type\":\"SPC\",\"request_id\":\"2\",\"GeneratorClientHello\":\"010100000000000000009E00000006363534333231BFE5BD7D83887028E389CCB8ED7AC40123E29C0A58B2A4D80C456BF6B7ECEF8621CF2500C234508D7A1C540F877082D6AEB205692E6E2DD723B930F1D7AB1FB0F6CC714B92D18CA315ECC5E5CCF4E9ADE865A64331674122103B8FEDD500DE44713C52F21246DFDEB6A5F76049B3F763FFC5F9C7D1483EFF2EAF7BA2CAE6DF5E9CC18D273BBE717C3371A2207EAFA35B7AC9C6400000000000\"}"}

thirdLen: 138
hello: 010100000000000000009e00000006363534333231bfe5bd7d83887028e389ccb8ed7ac40123e29c0a58b2a4d80c456bf6b7ecef8621cf2500c234508d7a1c540f877082d6aeb205692e6e2dd723b930f1d7ab1fb0f6cc714b92d18ca315ecc5e5ccf4e9ade865a64331674122103b8fedd500de44713c52f21246dfdeb6a5f76049b3f763ffc5f9c7d1483eff2eaf7ba2cae6df5e9cc18d273bbe717c3371a2207eafa35b7ac9c6400000000000
dest: 00000006363534333231bfe5bd7d83887028e389ccb8ed7ac40123e29c0a58b2a4d80c456bf6b7ecef8621cf2500c234508d7a1c540f877082d6aeb205692e6e2dd723b930f1d7ab1fb0f6cc714b92d18ca315ecc5e5ccf4e9ade865a64331674122103b8fedd500de44713c52f21246dfdeb6a5f76049b3f763ffc5f9c7d1483eff2eaf7ba2cae6df5e1442614e19fb6dc44b02588ecd000bed2fb7d32f
userId: 654321
pEncWBGx: bfe5bd7d83887028e389ccb8ed7ac40123e29c0a58b2a4d80c456bf6b7ecef8621cf2500c234508d7a1c540f877082d6aeb205692e6e2dd723b930f1d7ab1fb0f6cc714b92d18ca315ecc5e5ccf4e9ade865a64331674122103b8fedd500de44713c52f21246dfdeb6a5f76049b3f763ffc5f9c7d1483eff2eaf7ba2cae6df5e
pEncGx: 415102fce59a30c3a68eeda89f33beef6b2a69770d0b3c874584009dc95b3fb2a3afd078c6fddaed2fc083941366c9d20621d44fb4e39e07935e276714c15aa5be3249cf7eee01331125543f896087a8a3c9c1a87e5ea7a9914caa78b77e6d24995b048edcf4f10ad7cc25f480a6309a3e52393e34c9c09c18a981ec295eb37b
pGx: 94af6ddb184816ecb3fc02c273bac28c1625089e2f0e2054511842fd2b0b0c6326e72a45dddf8726fd3f30202ac98c3dce8a137e6e9e8dba63df63b49bceadee6b342757fa3fcb7c20c08bbb30919aa32cbae950eeafc96f290a0bdbb7f8bb8e57b7f5e181d8abbc456765ee072ef7c190ad21199cdb50b81082352027a5a9e9
secret: 4190a57b0cf2686273e8aae72282cf7ac49db69e3e8a38b7d4f3c668ce6d8bcbcd41c010033599d3930829361606f3f9c9a86140a5b5609d71ee00846ac5fc1db0793e88ce655b25e4431ffccc094d4fd03c4075f23cfae0591b41385f96eba7fbd59b7d3339ac2332a1f1bceea1bcc4450e503d31dd22571350e1f17e0d592d
hash2: 9cc18d273bbe717c3371a2207eafa35b7ac9c640
secret2: 3635343332314190a57b0cf2686273e8aae72282cf7ac49db69e3e8a38b7d4f3c668ce6d8bcbcd41c010033599d3930829361606f3f9c9a86140a5b5609d71ee00846ac5fc1db0793e88ce655b25e4431ffccc094d4fd03c4075f23cfae0591b41385f96eba7fbd59b7d3339ac2332a1f1bceea1bcc4450e503d31dd22571350e1f17e0d592d
hash3: 9cc18d273bbe717c3371a2207eafa35b7ac9c640
Pin OK :)

dest_hash: 58e812b08b8a64a31670efae36dd16a73c93010c
SKPrime: 8d8ce9ab5f971f3e50cc191b8d186e5f4ced3a5e
SKPrimeHash: 2b5967cd0102ff371d037d3078e4c55e677b8f9d
ctx: 87e41a5e95dcb0c88d4d8c358c522901
Pin accepted :)

sessionId: 4
SessionID: 4
Authorization successfull :)

Attempting to send command to tv
ws://192.168.178.22:8000/socket.io/1/websocket/ZzpDsufjsMYxHvdzxd4v
kdschlosser commented 5 years ago

OK I am going to work on this for a little bit. see what I can come up with.

p3g4asus commented 5 years ago

Attached you will find SSDP.log of my UE55H6400. @kdschlosser Thank you really much for your hard work I will investigate and further test to understand what should be saved to shorten the pairing process and send further commands without having to write the pin again. Obviously, having to write the pin each time makes the script pretty unusable for automation / batch purposes. I will report here my findings.

@andreas-bulling I am happy that it is working for you too.

SSDP.log

kdschlosser commented 5 years ago

ok so give this whirly bird a twirl.

https://github.com/kdschlosser/samsungctl/tree/H_J

samsungctl --host 192.168.1.1 --method encrypted

I still have to add the bits so you do not have to enter the pin each time.

kdschlosser commented 5 years ago

@p3g4asus

I need the whole folder structure. not just the single file.

andreas-bulling commented 5 years ago

ok so give this whirly bird a twirl.

https://github.com/kdschlosser/samsungctl/tree/H_J

samsungctl --host 192.168.1.1 --method encrypted

I still have to add the bits so you do not have to enter the pin each time.

Great - is this based on the latest SmartCrypto version?

p3g4asus commented 5 years ago

@kdschlosser Apparently only that file was created. I interrupted the scan after 5 minutes of dots.Did I make anything wrong? I used the develop branch of UPNP_device.

andreas-bulling commented 5 years ago
python3 -m samsungctl --host 192.168.178.60 --method encrypted                                                                             (H_J)
Traceback (most recent call last):
  File "/usr/local/Cellar/python/3.7.2_1/Frameworks/Python.framework/Versions/3.7/lib/python3.7/runpy.py", line 193, in _run_module_as_main
    "__main__", mod_spec)
  File "/usr/local/Cellar/python/3.7.2_1/Frameworks/Python.framework/Versions/3.7/lib/python3.7/runpy.py", line 85, in _run_code
    exec(code, run_globals)
  File "/Users/andreas/Desktop/samsungctl/samsungctl/__main__.py", line 274, in <module>
    main()
  File "/Users/andreas/Desktop/samsungctl/samsungctl/__main__.py", line 242, in main
    with Remote(config, log_level) as remote:
  File "/Users/andreas/Desktop/samsungctl/samsungctl/remote.py", line 23, in __init__
    self.remote = RemoteEncrypted(config)
  File "/Users/andreas/Desktop/samsungctl/samsungctl/remote_encrypted/__init__.py", line 14, in __init__
    self.StartPairing()
  File "/Users/andreas/Desktop/samsungctl/samsungctl/remote_encrypted/__init__.py", line 131, in StartPairing
    if self.CheckPinPageOnTv():
  File "/Users/andreas/Desktop/samsungctl/samsungctl/remote_encrypted/__init__.py", line 113, in CheckPinPageOnTv
    full_url = self.getFullUrl("/ws/apps/CloudPINPage")
  File "/Users/andreas/Desktop/samsungctl/samsungctl/remote_encrypted/__init__.py", line 97, in getFullUrl
    return "http://" + self.tvIP + ":" + self.tvPort + urlPath
AttributeError: 'RemoteEncrypted' object has no attribute 'tvIP'

UPDATE: self.StartPairing() is called before the necessary variables (including self.tvPort) are set in remote_encrypted/__init__.py. I fixed that and now it works (except for the fact that one has to enter the PIN each time as you mentioned and that the interactive mode does not wait for the pairing to finish)

p3g4asus commented 5 years ago

@kdschlosser Nice work! It does work. I had only to modify RemoteEncrypted init

    def __init__(self, config):
        if 'ctx' in config and config['ctx']:
            self.ctx = config['ctx']
        else:
            self.ctx = None

        if 'session_id' in config and config['session_id']:
            self.currentSessionId = config['session_id']

        self.SKPrime = False
        self.lastRequestId = 0

        self.UserId = "654321"
        self.AppId = "12345"
        self.deviceId = "7e509404-9d7c-46b4-8f6a-e2a9668ad184"
        self.tvIP = config['host']
        self.tvPort = "8080"
        self.aesLib = None
        self.connection = None
        self.config = config
        if not self.ctx:
            self.StartPairing()

Then I added

print("ctx %s " % self.config["ctx"])
print("ses %s " % self.currentSessionId)

after

print(websocket_url)

I also added two more command line arguments

    parser.add_argument(
        "--ctx",
        default=False,
        help="ctx"
    )
    parser.add_argument(
        "--session_id",
        default=False,
        help="Session ID"
    )

First execution command

py -3 -m samsungctl --host 192.168.25.32 --method encrypted KEY_MUTE

After the first execution I issued this command for the second execution

py -3 -m samsungctl --host 192.168.25.32 --ctx bb47c08ff166e9d508e4f095475d17e9 --session_id 3 --method encrypted KEY_POWEROFF

The values near ctx and session_id were printed after the first execution. In the second execution I did not have to enter the pin but the command run as expected. Many, many, many thanks.

kdschlosser commented 5 years ago

all is now fixed. I have to change out the print statements. other then that it is looking pretty good yes??

kdschlosser commented 5 years ago

@p3g4asus the UPNP sat there spinning it's wheels?? that is very odd, no errors??? it is defaulted to a timeout of 5 seconds.

kdschlosser commented 5 years ago

@p3g4asus

do me a favor. turn your TV on and on your computer open your web browser to these URL's

http://192.168.25.32:7676/smp_7_ http://192.168.25.32:7676/smp_2_ http://192.168.25.32:7676/smp_15_ http://192.168.25.32:7676/smp_25_

view the page source for each UR L and copy and save the source to separate files. zip the files up and attach them to a post.