kdschlosser / samsungctl

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

2019 7 Series (RU7xxx) deadlock #132

Open jnnks opened 4 years ago

jnnks commented 4 years ago

The code is stuck in a loop to wait for the TV to power on, but it's already running. The property change never occurrs.

The event loop does not seem to recognize the Tvs response.

# stuck at ctor
with samsungctl.Remote(config) as remote:
    print(remote.has_ssl())
GET /api/v2/ HTTP/1.1
Host: 192.168.0.66:8001
User-Agent: python-requests/2.22.0
Accept-Encoding: gzip, deflate
Accept: */*
Connection: keep-alive
HTTP/1.1 200 OK
content-type: application/json; charset=utf-8
content-length: 1315

"device":{
    "FrameTVSupport":"false",
    "GamePadSupport":"true",
    "ImeSyncedSupport":"true",
    "Language":"en_GB",
    "OS":"Tizen",
    "PowerState":"on",
    "TokenAuthSupport":"true",
    "VoiceSupport":"false",
    "WallScreenRatio":"0",
    "WallService":"false",
    "countryCode":"DE",
    "description":"Samsung DTV RCR",
    "developerIP":"0.0.0.0",
    "developerMode":"1",
    "duid":"uuid:x",
    "firmwareVersion":"Unknown",
    "id":"uuid:x",
    "ip":"192.168.0.66",
    "model":"19_MUSEL_UHD_BASIC",
    "modelName":"UE55RU7099UXZG",
    "name":"[TV] Samsung 7 Series (55)",
    "networkType":"wireless",
    "resolution":"3840x2160",
    "smartHubAgreement":"true",
    "ssid":"ac:22:05:e4:67:9b",
    "type":"Samsung SmartTV",
    "udn":"uuid:x",
    "wifiMac":"D0:D0:03:7E:2E:A1"
},
   "id":"uuid:x",
   "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\":\"false\"}\n",
   "name":"[TV] Samsung 7 Series (55)",
   "remote":"1.0",
   "type":"Samsung SmartTV",
   "uri":"http://192.168.0.66:8001/api/v2/",
   "version":"2.0.25"

my config:

    "host": "192.168.0.66",
    "port": 8001,
    "method": "websocket",
    "name": "r6",
    "description": "",
    "id": "",
    "token": "",
    "timeout": 1

The timeout settings does not seem to make a difference, as does method encrypted/websocket.

log:

RemoteWrapper.open()
RemoteWrapper.power()
RemoteWrapper.power => False
RemoteWrapper.power(value=True)
RemoteWrapper.power()
RemoteWrapper.power => False
RemoteWrapper.mac_address()
RemoteWrapper.mac_address => 'D0:D0:03:7E:2E:A1'
RemoteWrapper.mac_address()
RemoteWrapper.mac_address => 'D0:D0:03:7E:2E:A1'
RemoteWrapper.power()
RemoteWrapper.power => False
RemoteWrapper.open()
RemoteWrapper.mac_address()
RemoteWrapper.mac_address => 'D0:D0:03:7E:2E:A1'
RemoteWrapper.power()
RemoteWrapper.power => False
RemoteWrapper.open()
jnnks commented 4 years ago

It's a deadlock (receive_lock) because of recursive method calls.

open() lock power on -> power() open() #2

xMarkos commented 1 year ago

The problem is still present as of today. While inspecting the code, I realized that the offending recursion to the open() method can be prevented by using configuration setting paired=True. This workaround works even if the TV is not paired yet, at least with my TV model. Hope it saves somebody some nerves.

avg-I commented 9 months ago

Yeah, the problem is quite annoying. Especially because it's so hard to get through various indirections in the code. Like that power attribute actually means whether the websocket connection is made (so, has very little to do with the actual power state). And setting power sends a WOL packet and then just sleeps and then recurses to open.