Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

2022 The Frame art mode websocket commands do not work #108

Open
stephen opened this issue Apr 25, 2022 · 24 comments
Open

2022 The Frame art mode websocket commands do not work #108

stephen opened this issue Apr 25, 2022 · 24 comments

Comments

@stephen
Copy link

stephen commented Apr 25, 2022

Hello,

I'm trying to run this library against a 2022 frame tv (model: QN65LS03BAFXZA). Non-art mode commands seem to work fine (i.e. tv.run_app('3201606009684')), but art mode commands over the websocket hang and do not return.

Unfortunately, I don't have a non-2022 tv to test with, so I am not sure if this is an issue with my home setup, or a change in the 2022 models.

@CGDaveMac
Copy link

I am following this to see where the crossover is with a Homebridge project issue: tavicu/homebridge-samsung-tizen#519

I upgraded from a 2020 Frame to a 2022 model, and the art mode command worked for the first week and then stopped working a few days ago. I am not sure if there was a firmware update to the television during this time.

@crixyd
Copy link

crixyd commented Jul 9, 2022

Same issue occurs on 2022 model QA65LS03BAWXXY. Other ws requests work fine, but art mode requests time out. I own the TV and can test as needed.

@crixyd
Copy link

crixyd commented Jul 12, 2022

FWIW the developers over at https://github.com/tavicu/homebridge-samsung-tizen/wiki/Frame-TVs have reported that Samsung removed the Art Mode API in Tizen 6.5 and newer.

@vandenbrakel
Copy link

vandenbrakel commented Oct 11, 2022 via email

@norenjr
Copy link

norenjr commented Feb 3, 2024

Same issue, is there any workaround ?

@NickWaterton
Copy link

As of firmware 1622, the art WebSocket api is back!

With some changes, but mostly works as it used to.

@paultag
Copy link

paultag commented Apr 15, 2024

@NickWaterton do you happen to have any more information on what changes are needed? I just tried this out on a current generation frame tv at firmware 1622, and got the same error from ping.py

(samsungtvws.exceptions.ConnectionFailure: {'event': 'ms.channel.timeOut'})

The API endpoint has good information (lightly redacted below)

{'device': {'EdgeBlendingSupport': 'false', 'EdgeBlendingSupportGroup': '0', 'FrameTVSupport': 'true', 'GamePadSupport': 'true', 'ImeSyncedSupport': 'true', 'Language': 'en_US', 'OS': 'Tizen', 'PowerState': 'on', 'TokenAuthSupport': 'true', 'VoiceSupport': 'true', 'WallScreenRatio': '-1', 'WallService': 'false', 'countryCode': 'US', 'description': 'Samsung DTV RCR', 'developerIP': '0.0.0.0', 'developerMode': '0', 'duid': '', 'firmwareVersion': 'Unknown', 'id': '', 'ip': '', 'model': '22_PONTUSM_FTV', 'modelName': 'QN43LS03BDFXZA', 'name': 'Frame TV', 'networkType': 'none', 'resolution': '3840x2160', 'smartHubAgreement': 'true', 'ssid': '', 'type': 'Samsung SmartTV', 'udn': '', 'wifiMac': 'none'}, 'id': '', 'isSupport': '{DMP_DRM_PLAYREADY:false,DMP_DRM_WIDEVINE:false,DMP_available:true,EDEN_available:true,FrameTVSupport:true,ImeSyncedSupport:true,TokenAuthSupport:true,remote_available:true,remote_fourDirections:true,remote_touchPad:true,remote_voiceControl:true}\n', 'name': 'Frame TV', 'remote': '1.0', 'type': 'Samsung SmartTV', 'uri': 'http://10.x.y.z:8001/api/v2/', 'version': '2.0.25'}

@NickWaterton
Copy link

NickWaterton commented Apr 15, 2024

@paultag You have to use port 8002. ie

tv = SamsungTVWS('192.168.xxx.xxx', port=8002)

Then accept the connection on your TV (make sure TV is on), or use the saved token method (if you don't want to accept the connection every time).

# Autosave token to file
token_file = os.path.dirname(os.path.realpath(__file__)) + '/tv-token.txt'
tv = SamsungTVWS(host='192.168.xxx.xxx', port=8002, token_file=token_file)

This seems to be working. Not all commands work, get_thumbnail, send_image, get_brightness and get_color_temperature are not working. Don't know if these are simply not implemented, or not supported - or it the implementation has just changed.

get_api_version has been renamed api_version, and 'auto_rotation' has been renamed 'slideshow', so get_slideshow_status, and set_slideshow_status are the new commands - I don't think this library implements these command anyway, but they do work.

get_brightness and send_image are the command I would really like to get working.

Let me know what you find out.

@NickWaterton
Copy link

NickWaterton commented Apr 15, 2024

Update:

here is a list of commands that used to work on 2021 frame TV's. Don't know which ones work on the new api:

    get_api_version (or api_version) for new api
    get_artmode_status and set
    get_auto_rotation_status and set (or get_slideshow_status and set) for new api
    get_device_info
    get_content_list
    get_current_artwork
    get_thumbnail - downloads thumbnail in same format as uploaded
    send_image - uploads image jpg/png etc
    delete_image_list
    select_image - selects image to display (display optional)
    get_photo_filter_list
    set_photo_filter
    get_matte_list
    set_matte with content_id and matte_id
    change_matte with content_id and matte_id
    get_motion_timer (and set) valid values: "off","5","15","30","60","120","240", send settiing in "value"
    get_motion_sensitivity (and set) min 1 max 3 set in "value"
    get_color_temperature (and set) min -5 max +5 set in "value"
    get_brightness (and set) min 1 max 10 set in "value"
    get_brightness_sensor_setting (and set) on or off
    change_favourite with content_id value (or status) on or off (untested)

@NickWaterton
Copy link

Ok, figured out get_thumbnail, it's now get_thumbnail_list and accepts a list of content_ids as an argument content_id_list (like delete_list). Works for a list of 1, I haven't tried more.

You also have to use a secure socket connection if the conn_info returns secured : True.

Working on send_image now, it seems to work in a similar way.

@avwuff
Copy link

avwuff commented Apr 28, 2024

Tested Nick's changes and it works great! Was able to get my art mode changes unblocked. Thanks Nick!

@Emily
Copy link

Emily commented May 10, 2024

@NickWaterton any luck with send_image?

@NickWaterton
Copy link

Yes, got everything working.

@NickWaterton
Copy link

@Emily Check out my fork at https://github.com/NickWaterton/samsung-tv-ws-api

I also added an async_art.py module, and several async_art examples.

@xchwarze
Copy link
Owner

The problem is that if it is fixed for one version it breaks for the other... it would be necessary to find a way to determine which version of the service is running.
Just as the "tv control" service has its api that shows the version information and capabilities of the TV, this other service should have a similar one. Otherwise it can also be used as a version flag if one of the new apis fails.

Anyway I reiterate that the resulting code has to support both versions but those who have tizen 5 and 6 will be broken....

@NickWaterton
Copy link

Are we talking about the art api? Because get_api_version tells you what version of the api is available on the TV, and I’ve made all the common commands work for both versions.

There are version specific commands, eg get_auto_rotation_status is the old api command, and get_slideshow_status is the new api command, but you can use get_api_version to decide which to use, or just use the one for your model year (old is 2021 and earlier, new is 2022 and later).

@paultag
Copy link

paultag commented May 12, 2024

I forgot to reply here, I was also able to get my Frame working, but it was initially failing because the request was from a different /24 than the TV was on. After moving to the same subnet, the TV stopped resetting the connection and it looked a lot better. Thanks for tracking this down!

@suzukieng
Copy link

Hijacking this thread because @NickWaterton is on it... 😀 Has anyone had any luck with 2023 Frames?
I can connect to it (using both port 8001 and 8002, not sure what the difference is, haven't found any documentation on that), but most commands just block. For instance turning on art mode.

I turned on Developer mode (type 12345 in Apps) and registered my host computer's IP address as the 'host PC', not sure if that has any influence on the WebSocket API.

    tv = SamsungTVWS(host='192.168.1.58', token='<token>', port=8002, timeout=10)

    art_mode_supported = tv.art().supported() # True
    logging.info('Art mode supported: %s', art_mode_supported)

    logging.info('Enabling art mode')
    tv.art().set_artmode(True)  # this blocks
    logging.info('Art mode enabled')

This is what the TV is outputting when I do a curl -v http://<IP ADDRESS>:8001/api/v2/:

{
    "device":
    {
        "EdgeBlendingSupport": "false",
        "EdgeBlendingSupportGroup": "0",
        "FrameTVSupport": "true",
        "GamePadSupport": "true",
        "ImeSyncedSupport": "true",
        "Language": "en_GB",
        "OS": "Tizen",
        "PowerState": "on",
        "TokenAuthSupport": "true",
        "VoiceSupport": "true",
        "WallScreenRatio": "-1",
        "WallService": "false",
        "countryCode": "CH",
        "description": "Samsung DTV RCR",
        "developerIP": "192.168.1.101",
        "developerMode": "1",
        "duid": "uuid:<redacted>",
        "firmwareVersion": "Unknown",
        "id": "uuid:<redacted>",
        "ip": "192.168.1.58",
        "model": "22_PONTUSM_FTV",
        "modelName": "QE55LS03BAUXXN",
        "name": "Samsung The Frame 55",
        "networkType": "wireless",
        "resolution": "3840x2160",
        "smartHubAgreement": "true",
        "ssid": "<redacted>",
        "type": "Samsung SmartTV",
        "udn": "uuid:<redacted>",
        "wifiMac": "<redacted>"
    },
    "id": "uuid:<redacted>",
    "isSupport": "{\"DMP_DRM_PLAYREADY\":\"false\",\"DMP_DRM_WIDEVINE\":\"false\",\"DMP_available\":\"true\",\"EDEN_available\":\"true\",\"FrameTVSupport\":\"true\",\"ImeSyncedSupport\":\"true\",\"TokenAuthSupport\":\"true\",\"remote_available\":\"true\",\"remote_fourDirections\":\"true\",\"remote_touchPad\":\"true\",\"remote_voiceControl\":\"true\"}\n",
    "name": "Samsung The Frame 55",
    "remote": "1.0",
    "type": "Samsung SmartTV",
    "uri": "http://192.168.1.58:8001/api/v2/",
    "version": "2.0.25"
}

@NickWaterton
Copy link

NickWaterton commented Oct 31, 2024

You need to use port 8002 (this is the secure websockets port). 8001 will not work.

Also, you need to understand how the frame TV works.

There are 4 endpoints to consider. One http(s) which is what you show in your post, and what is used to determine if art mode is supported, plus three websocket end points.

The websocket endpoints are:

  • Remote control
  • Art mode control
  • App control

The Python library combines all these into one interface. The remote control websocket requires a token, which is generated by accepting the connection in the TV, and has to be saved, to be reused in future connections (or you will be requested to accept the connection on the TV every time).

The art mode websocket does not need a token, and is what you are using when you use the tv.art() construct.

I do NOT recommend using the tv.art() construct, as it is an old api, and may not work well. Instead you should use the asynchronous tv interface as demonstrated in the example folder program async_art.py. Run this with your tv ip address as an argument, and see what is output.

NOTE: the way of turning art mode on, generally is to send the TV POWER_TOGGLE key. Also, you often cannot turn the TV on from fully off, without using WOL.

Sending tv.art().set_artmode(True) would only work if the TV was on and playing, and apart from not being the recommended async command, may not work correctly. Sending the remote control key to toggle power is the recommended way (for which you have to know if art mode is on or not using get_artmode(), and if the tv is on or not. There are commands in the async library that do this for you. Read the async .py files to understand how it works.

Please thank Samsung for making this so convoluted.

Let me know what the output of async_art.py is - that should let you know if the api is working.

I am obviously talking about my fork of this library. The 2023 Frame TV uses a different api to the previous 2021 and earlier api, so this library will not work with later Frame TV’s - my fork is updated with the new api (but still supports the old).

My fork is here https://github.com/NickWaterton/samsung-tv-ws-api

@suzukieng
Copy link

@NickWaterton thank you so much, that was supremely helpful. It's a side project of mine, I will keep you posted on my progress.

@suzukieng
Copy link

Hey @NickWaterton, I tried the async_art.py from your fork (and of course installed it first) but it terminates really early in the tv.start_listening() call with OSError: [Errno 65] No route to host. I'm on Python 3.10.12.

The snippet:

import asyncio
import logging
import sys

from samsungtvws.async_art import SamsungTVAsyncArt


async def main():
    hostname = '192.168.1.13' if len(sys.argv) < 2 else sys.argv[1]
    port = 8002

    tv = SamsungTVAsyncArt(host=hostname, port=port)
    print(f'Attempting to connect to {hostname}:{port}...')
    await tv.start_listening()
    print('Successfully connected')

    supported = await tv.supported()
    if not supported:
        logging.error('Art mode is NOT supported')
        sys.exit(1)

    # get api version 4.3.4.0 is new api, 2.03 is old api
    api_version = await tv.get_api_version()
    print(f'TV API version: {api_version}')
    await tv.close()

asyncio.run(main())

The stack trace:

Traceback (most recent call last):
  File "/Users/ahs/pixelverse/family-frame-controller/controller.py", line 27, in <module>
    asyncio.run(main())
  File "/Users/ahs/.pyenv/versions/3.10.12/lib/python3.10/asyncio/runners.py", line 44, in run
    return loop.run_until_complete(main)
  File "/Users/ahs/.pyenv/versions/3.10.12/lib/python3.10/asyncio/base_events.py", line 649, in run_until_complete
    return future.result()
  File "/Users/ahs/pixelverse/family-frame-controller/controller.py", line 14, in main
    await tv.start_listening()
  File "/Users/ahs/pixelverse/family-frame-controller/venv/lib/python3.10/site-packages/samsungtvws-2.6.0-py3.10.egg/samsungtvws/async_art.py", line 99, in start_listening
  File "/Users/ahs/pixelverse/family-frame-controller/venv/lib/python3.10/site-packages/samsungtvws-2.6.0-py3.10.egg/samsungtvws/async_connection.py", line 89, in start_listening
  File "/Users/ahs/pixelverse/family-frame-controller/venv/lib/python3.10/site-packages/samsungtvws-2.6.0-py3.10.egg/samsungtvws/async_art.py", line 77, in open
  File "/Users/ahs/pixelverse/family-frame-controller/venv/lib/python3.10/site-packages/samsungtvws-2.6.0-py3.10.egg/samsungtvws/async_connection.py", line 58, in open
  File "/Users/ahs/pixelverse/family-frame-controller/venv/lib/python3.10/site-packages/websockets/legacy/client.py", line 654, in __await_impl__
    _transport, protocol = await self._create_connection()
  File "/Users/ahs/.pyenv/versions/3.10.12/lib/python3.10/asyncio/base_events.py", line 1076, in create_connection
    raise exceptions[0]
  File "/Users/ahs/.pyenv/versions/3.10.12/lib/python3.10/asyncio/base_events.py", line 1060, in create_connection
    sock = await self._connect_sock(
  File "/Users/ahs/.pyenv/versions/3.10.12/lib/python3.10/asyncio/base_events.py", line 969, in _connect_sock
    await self.sock_connect(sock, address)
  File "/Users/ahs/.pyenv/versions/3.10.12/lib/python3.10/asyncio/selector_events.py", line 501, in sock_connect
    return await fut
  File "/Users/ahs/.pyenv/versions/3.10.12/lib/python3.10/asyncio/selector_events.py", line 509, in _sock_connect
    sock.connect(address)
OSError: [Errno 65] No route to host

I was first thinking some kind of network issue, but I can reach the TV using that IP and port with a curl -v --insecure https://192.168.1.13:8002/api/v2/. I get the JSON below.

I'm pretty clueless at this point, do you have any idea? The error message suggest a low-level networking issue, but then the cURL should fail too... I was first thinking maybe an issue with the TLS trust (Samsung's self-signed certificate), but it sounds lower-level than that.

{"device":{"EdgeBlendingSupport":"false","EdgeBlendingSupportGroup":"0","FrameTVSupport":"true","GamePadSupport":"true","ImeSyncedSupport":"true","Language":"en_GB","OS":"Tizen","PowerState":"on","TokenAuthSupport":"true","VoiceSupport":"true","WallScreenRatio":"-1","WallService":"false","countryCode":"CH","description":"Samsung DTV RCR","developerIP":"192.168.1.101","developerMode":"1","duid":"uuid:43bc17ab-017c-4667-8ada-c15c16663c51","firmwareVersion":"Unknown","id":"uuid:43bc17ab-017c-4667-8ada-c15c16663c51","ip":"192.168.1.13","model":"22_PONTUSM_FTV","modelName":"QE55LS03BAUXXN","name":"Samsung The Frame 55","networkType":"wireless","resolution":"3840x2160","smartHubAgreement":"true","ssid":"d6:21:f9:3f:32:ba","type":"Samsung SmartTV","udn":"uuid:43bc17ab-017c-4667-8ada-c15c16663c51","wifiMac":"70:09:71:83:68:D2"},"id":"uuid:43bc17ab-017c-4667-8ada-c15c16663c51","isSupport":"{\"DMP_DRM_PLAYREADY\":\"false\",\"DMP_DRM_WIDEVINE\":\"false\",\"DMP_available\":\"true\",\"EDEN_available\":\"true\",\"FrameTVSupport\":\"true\",\"ImeSyncedSupport\":\"true\",\"TokenAuthSupport\":\"true\",\"remote_available\":\"true\",\"remote_fourDirections\":\"true\",\"remote_touchPad\":\"true\",\"remote_voiceControl\":\"true\"}\n","name":"Samsung The Frame 55","remote":"1.0","type":"Samsung SmartTV","uri":"https://192.168.1.13:8002/api/v2/","version":"2.0.25"}

@suzukieng
Copy link

@NickWaterton I figured it out... there's some kind of issue when launching the Python script from the IDE (PyCharm), even though it's supposed to be using the virtual environment. Launching it script from the shell works... But now it's just stucking in the await tv.start_listening() call. I'll try debugging a bit more. It's a shame Samsung is making this so difficult.

@suzukieng
Copy link

@NickWaterton ... I got it to work! Power-cycled the TV and put it into art mode, and it suddenly started responding. I managed to change art mode settings (e.g. brightness), upload a picture (stored in My Photos). Thank you so much for providing your fork and the async art library.

@NickWaterton
Copy link

You are welcome! Glad you could get it to work.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests